The method in step 02 lives or dies on log reading. Logs are how Render tells you what happened; everything else is inference. This step is the cheat sheet: where each log lives, how to navigate it without scrolling for ten minutes, and the CLI one-liners that beat the Render Dashboard for triage.
The three log surfaces
Render writes logs to three places, and a lot of confusion comes from looking in the wrong one:
flowchart LR events["Service<br/>Events feed"] deploy["Deploy logs<br/>(per deploy)"] runtime["Runtime logs<br/>(per service)"] events -->|"click a deploy"| deploy deploy -->|"build succeeded,<br/>now the service is live"| runtime
| Log type | Lives on | Contents | When you want it |
|---|---|---|---|
| Events feed | Service page → Events | Timeline of deploys, env var changes, scaling actions | ”What changed and when?” |
| Deploy log | Click a deploy in Events | Build output + pre-deploy output for that one deploy | Build or pre-deploy failed |
| Runtime log | Service page → Logs | Stdout/stderr from the running service | Service is live but misbehaving, or boot is failing |
The boundary between the deploy log and the runtime log is the moment the build succeeds and Render starts your startCommand. If your service crashes on boot, the crash is in the runtime log, not the deploy log - even though the deploy itself is marked as failed.
Anatomy of a deploy log
Every deploy log has the same shape, in order:
==> Cloning from https://github.com/your-org/your-repo==> Checking out commit abc123 in branch main==> Using Node version 20.11.0 (default)==> Running build command 'npm ci && npm run build'... build command output ...==> Uploading build...==> Uploaded build successfully==> Running pre-deploy command 'npm run db:migrate'... pre-deploy output ...==> Pre-deploy command succeeded==> Build successful 🎉==> Deploying...==> Running 'npm start'... your application's stdout starts here ...The ==> lines are Render’s own logging. They mark phase boundaries - those are your ruler. Everything between two ==> lines belongs to one phase, and the phase tells you which family of error you’re looking at.
A few patterns worth memorising:
==> Build failedbefore any application output → buildCommand returned non-zero. See step 04.==> Pre-deploy command failed→ preDeployCommand returned non-zero. Often a migration or a missing env var.==> Deploy timed outwith no obvious crash → yourstartCommandis running but not binding the port, or your health check is failing. See step 05.==> Deploy failedafter application output → your app crashed on boot. See step 06.
Finding the first error fast
The Render Dashboard’s deploy log viewer has a built-in search box. Use it. Don’t scroll.
- Open the failed deploy From the service’s Events feed, click the deploy row labelled
Deploy failed(orBuild failed). - Search for `error` Case-insensitive search highlights every match. The Render Dashboard wires next/previous match like a normal text editor.
- Jump to the first match, not the last Errors at the top are causes. Errors at the bottom are usually the process exiting because of the cause.
- Read 5 lines above and 10 lines below Context above gives you “what was Render trying to do?”; context below gives you the stack trace.
The first error is almost never on the last screen. Train yourself to scroll up when you open a failed deploy, not down.
The CLI: faster for triage loops
Once you’ve diagnosed two or three failures from the Render Dashboard, the click cost adds up. The CLI is faster:
# 1. Find the failing service's IDrender services -o json | jq -r '.[] | select(.service.name == "api") | .service.id'
# 2. List its recent deploys, with statusrender deploys list srv-xxxxx -o json \ | jq -r '.[] | "\(.deploy.id)\t\(.deploy.status)\t\(.deploy.commit.id)"' \ | head -5
# 3. Stream the deploy's logs (build + runtime if applicable)render logs -r srv-xxxxx --start 30m --limit 1000For the most common loop - “show me the last error from the most recent failed deploy” - this one-liner is gold:
SRV=srv-xxxxxrender logs -r "$SRV" --start 1h --level error --limit 50 \ | head -20--level error filters server-side, so you don’t pull megabytes of info-level logs over the wire. head -20 is the “give me the first matches, not the last” knob.
The four signals you’re looking for
Most of triage is pattern recognition. Four log signals cover 90% of failures:
1. Stack traces
TypeError: Cannot read properties of undefined (reading 'split') at parseConfig (/opt/render/project/src/config.js:42:18) at Object.<anonymous> (/opt/render/project/src/app.js:8:14) at Module._compile (node:internal/modules/cjs/loader:1256:14) ...A stack trace is gold: it tells you the language, the file, the line, and the cascade. The top frame is the crash site; the bottom frames are how you got there. Open the file at the line number.
2. ==> lines from Render
==> Detected service running on port 10000==> Detected service running on port 8080==> Your service is live 🎉==> No open ports detected, continuing to scan...==> Timed out==> Deploy failedThese tell you what Render saw. They’re the most reliable narrator of the boot process. Step 05 is mostly about decoding these.
3. Exit codes and signals
==> Application exited with code 1==> SIGTERM received, shutting down gracefully==> Application exited with code 0==> Out of memory! Process was killed==> Application exited with code 137Exit code 0 = clean. Non-zero = error. Code 137 = OOM kill by the kernel. SIGTERM = Render asked the process to shut down (deploy, scale-down, or restart).
4. Render-specific warnings
==> Your service is using Node 18, but your package.json specifies "node": ">=20".==> Set NODE_VERSION to override the default.Render emits informational warnings about version mismatches, missing health checks, and other configuration smells. They show up in the deploy log between ==> lines. Don’t skim past them - they’re often the diagnosis already.
A working example
Here’s a real shape of a deploy log for a build that failed. Read it top-to-bottom and try to spot the first error before you read my annotation:
==> Cloning from https://github.com/example/app==> Checking out commit 4f2a91c in branch main==> Using Node version 18.20.0 (default)==> Running build command 'npm ci && npm run build'npm warn deprecated some-old-package@1.0.0> app@1.0.0 build> next buildSyntaxError: Unexpected token '??=' at internalCompileFunction (node:internal/vm:73:18) at wrapSafe (node:internal/modules/cjs/loader:1153:20) ...npm ERR! code 1==> Build failed 😞What the method tells us:
- Phase: build. The
Build failedmarker confirms it. - First error:
SyntaxError: Unexpected token '??='on line 8. - Render’s clue: line 3 - Node 18 is the default.
- Hypothesis: the
??=(logical-nullish-assignment) operator needs Node 16+. Wait, Node 18 has it. So what gives? Read the error again: it points tonode:internal/vm, which means the project’s own build tooling (next build) is choking on the syntax. The fix is the same as a version mismatch - bump to Node 20 to match the project’senginesfield, which is almost certainly set.
We dig into this exact failure in step 04. For now, the takeaway is that lines 3, 8, and the Build failed marker together gave you the diagnosis without ever scrolling.
Log retention and freshness
Two operational details that matter when you’re chasing an old failure:
- Logs are eventually consistent. A line that just happened might take 1-2 seconds to appear. For live triage,
render logs --tailis the most reliable view. - Retention depends on your plan. If
--start 7dreturns less than you expected, your plan’s retention window is shorter than that. The Render Dashboard’s log explorer will simply stop returning rows; the CLI does the same silently. For long-term forensics, ship logs to an external sink (see Render’s log streaming docs).
What you learned
- Three log surfaces: Events feed (timeline), deploy logs (build + pre-deploy), runtime logs (boot + live)
- Deploy logs and runtime logs are different views. A 'Deploy failed' with a green build means look at runtime logs
- `==>` lines are Render's own narration - they mark phase boundaries and emit warnings you should actually read
- Search for `error` and jump to the FIRST match, not the last. Context is 5 lines above and 10 below
- CLI shortcut for triage: `render logs -r $SRV --start 1h --level error --limit 50 | head -20`
- Four signals cover 90% of failures: stack traces, `==>` lines, exit codes/signals, and Render warnings