The problem

Your application runs across five Pods. Something is wrong. You open a terminal for each Pod:

kubectl logs -f my-app-7d9f8b6c4-xk2p9
kubectl logs -f my-app-7d9f8b6c4-zt7lm
kubectl logs -f my-app-7d9f8b6c4-p9x3k
# ...and so on

Five terminals. Five streams. You switch between them trying to correlate events by timestamp. Meanwhile the Pod you are not watching is the one logging the error.

kubectl logs works for one Pod. Real applications do not run in one Pod.

Enter stern

stern tails logs from multiple Pods at once, matched by name pattern or label selector. Output is color-coded per Pod so you can tell which line came from where.

One command. All matching Pods. One stream.

It still respects RBAC and namespace scope — if you cannot list Pods, stern cannot tail them either.

Installation

Via Homebrew (macOS/Linux):

brew install stern

Via Krew:

kubectl krew install stern

After Krew, the command may be kubectl stern depending on your setup; the standalone binary is stern.

Via binary:

Download from github.com/stern/stern/releases.

Use kubectx and kubens to land in the right cluster first; k9s is great for picking a Deployment, stern for watching all its Pods at once.

Basic usage

# Tail all pods matching a name pattern
stern my-app

# Tail pods in a specific namespace
stern my-app -n production

# Tail pods across all namespaces
stern my-app --all-namespaces

# Tail pods matching a label selector
stern -l app=my-app

# Tail only a specific container in multi-container pods
stern my-app -c nginx

# Show logs from the last 10 minutes
stern my-app --since 10m

The features that matter

Color-coded output. Each Pod gets its own color. At a glance you know which Pod logged what — no more squinting at name prefixes.

Regex pattern matching. The Pod name argument is a regular expression:

# Match all pods starting with "api"
stern "api.*"

# Match both frontend and backend pods
stern "frontend|backend"

Label selectors. Target Pods by label instead of name:

stern -l environment=staging,tier=frontend

Output templates. Customize log format with Go templates:

# Show only the log message, no pod name prefix
stern my-app --template '{{.Message}}'

# Include timestamp and pod name
stern my-app --template '{{.PodName}} {{.Message}}'

Filtering with grep. Pipe stern output like any Unix stream:

# Show only error lines
stern my-app | grep -i error

# Show lines containing a specific request ID
stern my-app | grep "req-id-abc123"

A real debugging scenario

You see intermittent 500 errors. You do not know which Pod is responsible. With stern:

stern my-app -n production | grep "500"

One command. All Pods. Errors highlighted as they happen. You see my-app-7d9f8b6c4-zt7lm is the only one throwing 500s — that Pod sits on a node with memory pressure. Mystery solved in two minutes instead of twenty.

For ownership before you tail, kubectl tree shows which ReplicaSet belongs to which Deployment. For single-Pod deep dives, plain kubectl logs still belongs in the loop.

stern vs kubectl logs

kubectl logsstern
Multiple podsOne at a timeAll matching pods
Color codingNoPer pod
Regex matchingNoYes
Label selectorsYesYes
Output templatesNoYes
Follow new podsNoAutomatically

The last row matters: if a Pod restarts or a new Pod is created while stern is running, stern picks it up automatically. kubectl logs -f drops the stream on restart.

Summary

Installbrew install stern or kubectl krew install stern
Best forDebugging across multiple pods, correlating events
Killer featureColor-coded multi-pod streaming with regex matching
Pro tipCombine with grep for targeted filtering
GitHubgithub.com/stern/stern

Once you have debugged a multi-pod issue with stern, going back to individual kubectl logs feels like reading one page of a book at a time.