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
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.
| Flag | What it does |
|---|---|
-r, --resources | One or more service IDs (or comma-separated). Required. |
--tail | Stream new logs as they arrive (like tail -f). |
--start / --end | Time range (ISO 8601 or relative, e.g. 5m for “5 minutes ago”). |
--limit | Max number of lines (default 100). |
--text | Filter by substring on the log message. |
--level | Filter by level (info, warning, error). |
-o json | Structured output, one event per line. |
Tail in real time
The “I just clicked deploy and want to watch the boot” workflow:
SRV=$(render-id api)render logs -r "$SRV" --tailHit Ctrl+C to stop. Add a second service to merge two streams:
render logs -r "$(render-id api),$(render-id worker)" --tailLines 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.
render logs -r "$SRV" --start 30m --limit 500Relative times accept s (seconds), m (minutes), h (hours), d (days). For absolute ISO 8601:
render logs -r "$SRV" \ --start 2026-05-21T20:00:00Z \ --end 2026-05-21T20:15:00ZThe CLI pages through results up to --limit. For deep dives, bump the limit and pipe to a file:
render logs -r "$SRV" --start 24h --limit 10000 > yesterday.logFilter as you fetch
Two filters are baked into the CLI - use them when you can; they cut the volume server-side and save bandwidth.
render logs -r "$SRV" --level error --start 1hrender logs -r "$SRV" --text "DATABASE_URL" --start 1hFor anything more complex, get JSON and pipe to jq:
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
render logs -r "$SRV" --level error --start 1hCount requests per HTTP status (for a web service)
render logs -r "$SRV" --start 1h --limit 10000 -o json \ | jq -r '.message' \ | grep -oE 'status=[0-9]+' \ | sort | uniq -c | sort -rnAdjust 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:
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:
render logs -r "$SRV" --tail | less -Rless -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.
#!/usr/bin/env bashset -euo pipefailexport RENDER_API_KEY="${RENDER_API_KEY:?must be set}"export RENDER_OUTPUT=jsonSRV="${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 0fi
echo "Deploy failed. Last 200 log lines:" >&2render logs -r "$SRV" --start 30m --limit 200 >&2exit 1You’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:
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
| Behavior | Why it matters |
|---|---|
| Logs are eventually-consistent | A 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 plan | The 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-side | If you’re paging through gigabytes, --text is much cheaper. For complex regex or post-processing, JSON + jq. |
| Build logs are separate from runtime logs | render 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. |
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