Render Tutorials
Render CLI for power users

Tail, filter, and triage logs

⏱ 9 min

When something’s wrong with a service, the question is almost always “show me the logs from the last 5 minutes.” The Render Dashboard does this with a click; the CLI does it with render logs and gives you everything grep and jq can do on top.

The shape of a logs command

Terminal
render logs -r <SERVICE_ID> [flags]

The -r (or --resources) flag is required and accepts one or more service IDs. The CLI is happy to tail multiple services into one stream, which is useful for tracking a request across a web service and a worker.

FlagWhat it does
-r, --resourcesOne or more service IDs (or comma-separated). Required.
--tailStream new logs as they arrive (like tail -f).
--start / --endTime range (ISO 8601 or relative, e.g. 5m for “5 minutes ago”).
--limitMax number of lines (default 100).
--textFilter by substring on the log message.
--levelFilter by level (info, warning, error).
-o jsonStructured output, one event per line.

Tail in real time

The “I just clicked deploy and want to watch the boot” workflow:

Terminal
SRV=$(render-id api)
render logs -r "$SRV" --tail

Hit Ctrl+C to stop. Add a second service to merge two streams:

Terminal
render logs -r "$(render-id api),$(render-id worker)" --tail

Lines are prefixed with the service name, so you can still tell them apart.

Look back in time

Tailing is for live problems; for “what happened during the deploy 10 minutes ago” you want a bounded window.

Terminal
render logs -r "$SRV" --start 30m --limit 500

Relative times accept s (seconds), m (minutes), h (hours), d (days). For absolute ISO 8601:

Terminal
render logs -r "$SRV" \
--start 2026-05-21T20:00:00Z \
--end 2026-05-21T20:15:00Z

The CLI pages through results up to --limit. For deep dives, bump the limit and pipe to a file:

Terminal
render logs -r "$SRV" --start 24h --limit 10000 > yesterday.log

Filter as you fetch

Two filters are baked into the CLI - use them when you can; they cut the volume server-side and save bandwidth.

Terminal
render logs -r "$SRV" --level error --start 1h
Terminal
render logs -r "$SRV" --text "DATABASE_URL" --start 1h

For anything more complex, get JSON and pipe to jq:

Terminal
render logs -r "$SRV" --start 1h -o json --limit 5000 \
| jq -r 'select(.severity == "error" and (.message | test("timeout|refused"))) | "\(.timestamp)\t\(.message)"'

The JSON shape per line typically includes timestamp, severity, message, and a labels map (with instance, region, etc.). Run a single line with jq '.' to confirm the exact field names in your workspace - log shape can vary slightly between service types.

Common one-liners

Show only errors from the last hour

Terminal
render logs -r "$SRV" --level error --start 1h

Count requests per HTTP status (for a web service)

Terminal
render logs -r "$SRV" --start 1h --limit 10000 -o json \
| jq -r '.message' \
| grep -oE 'status=[0-9]+' \
| sort | uniq -c | sort -rn

Adjust the grep regex to match your log format (status_code, status, JSON access logs, etc.).

Tail one specific deploy

render deploys list gives you the deploy ID; logs scope to a service, not a deploy, but you can bound by the deploy’s createdAt / finishedAt:

Terminal
read -r start finish < <(render deploys list "$SRV" -o json \
| jq -r '.[0].deploy | "\(.createdAt) \(.finishedAt // (now | todate))"')
render logs -r "$SRV" --start "$start" --end "$finish"

(Subshell + heredoc is overkill on one line - break it out into a helper script if you do this often.)

Stream into less

When you want to scroll-search live output without losing buffering:

Terminal
render logs -r "$SRV" --tail | less -R

less -R preserves color codes. Ctrl+C to stop the stream; q to quit less.

Capture logs on deploy failure (capstone preview)

The single most useful logs pattern in CI: when a deploy fails, dump the last 200 lines into the workflow output so you can debug without leaving the PR.

ci-deploy-with-logs.sh
#!/usr/bin/env bash
set -euo pipefail
export RENDER_API_KEY="${RENDER_API_KEY:?must be set}"
export RENDER_OUTPUT=json
SRV="${RENDER_SERVICE_ID:?must be set}"
if render deploys create "$SRV" --wait --confirm > deploy.json; then
echo "Deploy succeeded: $(jq -r '.deploy.commit.id' deploy.json)"
exit 0
fi
echo "Deploy failed. Last 200 log lines:" >&2
render logs -r "$SRV" --start 30m --limit 200 >&2
exit 1

You’ll see this exact shape in step 10’s GitHub Actions workflow, with a couple of extras (timestamps, GitHub log-grouping annotations).

Multi-service triage

When a bug crosses services - say a web request that fans out to a worker - tail both at once:

Terminal
render logs -r "$(render-id api),$(render-id worker)" --tail \
| grep --line-buffered -E 'request_id=abc123|job_id=xyz789'

grep --line-buffered is the trick that keeps live output flowing through the pipe without buffering for a 4KB block.

A few things to know

BehaviorWhy it matters
Logs are eventually-consistentA line that just happened might take a second or two to show up. For real-time debugging, --tail is more reliable than repeated short queries.
Retention varies by planThe CLI doesn’t surface “history is exhausted” - if --start 7d returns less than you expect, your retention window is shorter than that.
--text is server-side, grep is client-sideIf you’re paging through gigabytes, --text is much cheaper. For complex regex or post-processing, JSON + jq.
Build logs are separate from runtime logsrender logs shows runtime/service logs by default. Build failures often live in the deploy’s build log, which is in render deploys list output as a URL.
A teammate asks you to dump everything the API service logged during last night's incident (between 2:00 and 2:15 a.m. UTC). Which command is closest to right?

What you learned

  • `render logs -r SRV --tail` is the live debugger; `--start` and `--end` is the historical one
  • Filter server-side with `--level` and `--text` when you can; pipe `-o json` to `jq` when you can't
  • `render logs` shows runtime logs. Build logs live on the deploy object via `render deploys list`
  • The 'fail + dump logs' pattern at the end of this step is the same one you'll plug into GitHub Actions in step 10