Troubleshooting a stuck or failed deployment
A step-by-step guide to diagnosing and recovering an app deploy that is stuck, failed, or crash-looping - for any app type.
Troubleshooting a stuck or failed deployment
Most deployments build and start within a couple of minutes. When one doesn't, open the Troubleshoot tab on your deployment page. It reads your app's current state, tells you what's wrong in plain language, and gives you one-click fixes. This article covers the same steps if you prefer to read them through first.
A deploy moves through these states: pending → building → deploying → active. If it never reaches active, one of the scenarios below applies.
My deploy is stuck (no progress for 10+ minutes)
A deploy sitting in building or deploying for more than about ten minutes usually means the build hung or the build machine dropped the job. It will not finish on its own.
- Open the Troubleshoot tab. If it has been stuck long enough, you'll see a This deploy looks stuck card.
- Click Cancel stuck deploy. This marks the stuck attempt as failed. It does not affect a version of your app that is already running, only the hung attempt.
- Click Retry deploy to start a fresh deploy. Your subdomain, ports, and secrets are carried over automatically.
If retries keep getting stuck at the same step, check the build and deploy logs (below) for the last line before it froze.
My deploy failed
Work through the checklist on the Troubleshoot tab, fix the cause, then click Retry deploy. The most common causes:
- A missing environment variable or secret. A missing
DATABASE_URLor API key is the number-one cause of a failed start. Add it under the Secrets tab; changes apply on the next deploy or retry. - The app listens on the wrong port. We forward traffic to your container port (default
3000). Your app must listen on that port, on0.0.0.0(notlocalhost/127.0.0.1). Adjust it under the Networking tab. - A build error. Open the build and deploy logs to see the exact command that failed.
- The wrong branch or an unbuildable commit. Confirm you deployed the branch you expect.
My app is up but keeps restarting (crash loop)
The container built fine but crashes right after starting, so it restarts over and over. This is almost always a runtime problem, not a build one:
- Open the Logs tab and read the live container logs. The crash reason (a thrown error, a missing variable, a failed database connection) is printed there.
- Fix the cause, most often a missing secret or environment variable under Secrets.
- If needed, use Retry or Restart from the deployment page.
App-type specific checks
Static sites (build + serve)
- Your build command must produce files in the configured output directory (for example
dist,build, orout). If the folder name doesn't match, the served site will be empty. - A failing build command stops the deploy before the site is served. The build logs show the exact error.
Docker apps
- Your
Dockerfilemust start a process that listens on your container port. If your app listens on a different port, update it under Networking. - A
Dockerfilebuild error fails the deploy. The build logs show which layer or command failed.
Node.js and custom start commands
- Your app must bind to
0.0.0.0:, notlocalhost. A server bound to127.0.0.1is unreachable from outside the container and shows as unhealthy. - Your start command must launch a long-running server. A command that runs once and exits is treated as a crash.
Prebuilt Docker images
- The image must exist and listen on your configured container port.
Where to find the logs
There are two kinds of logs, both reachable from your deployment page:
- Build and deploy logs (Troubleshoot tab): the output captured while building and starting the deploy. This is where a failed build reports its error.
- Live container logs (Logs tab): fresh output from the running container. This is where a running or crash-looping app reports its errors.
Still stuck?
If you've worked through the checklist and retries still fail, contact support from your dashboard and mention your app name and what the build logs show. We can see the host-side details you can't and will take it from there.