# Fixing deployments that hang after the build step succeeds

**Author:** Anna Z.

---

## Fixing deployments that hang after the build step succeeds

If your deployment shows the build finishing but then sits forever in "Building" with no error, with checks and domain assignment stuck pending, this guide is for you.

## What's happening

Vercel waits for your build command to finish _and exit_ before moving on to upload, checks, and domain assignment. If your build does its work but the underlying Node.js process never exits (because something like a timer, open connection, or background task is still running), Vercel has no way to know the build is done. The deployment stays in "Building" until you cancel it.

This usually doesn't show up locally. When you run the build on your laptop, you stop it with Ctrl+C and don't notice anything is wrong. On Vercel there's nothing to send that signal.

The fix is to force your build process to exit once your framework is done.

## How to confirm this is your issue

Open the build logs for the stuck deployment. You should see:

- Your framework's success messages (pages prerendered, server built, output generated, etc.).
  
- Logs end shortly after that, with no "Build Completed" line.
  
- No errors anywhere in the build.
  

If you see actual errors or the build stops part-way through, this isn't the right guide.

## Step 1: Unblock your deployments

Add a small hook to your config that forces the build to exit cleanly once your framework finishes. Pick the snippet for your setup.

**Nuxt** (`nuxt.config.ts`):

`export default defineNuxtConfig({ nitro: { hooks: { compiled() { setTimeout(() => process.exit(0), 0) } } } })`

**Vite** (`vite.config.ts`):

`import { defineConfig } from 'vite' export default defineConfig({ plugins: [ { name: 'force-exit-after-build', apply: 'build', closeBundle() { setTimeout(() => process.exit(0), 0) } } ] })`

**Other frameworks:** look for a hook called something like `closeBundle`, `done`, `compiled`, or `onBuildEnd`, and call `setTimeout(() => process.exit(0), 0)` from it.

Commit, push, and your next deployment should complete. Your site is now unblocked.

This is a workaround, not a permanent fix. It tells Node "we're done, stop waiting" without addressing what was keeping it busy. For most teams that's fine; if you want to find and fix the underlying cause, continue to step 2.

## Step 2: Find the actual cause

Install a small diagnostic tool that prints what's still running when your build finishes:

`npm install --save-dev why-is-node-running`

Then update the same hook to print the diagnostic output before exiting.

**Nuxt:**

`import whyIsNodeRunning from 'why-is-node-running' export default defineNuxtConfig({ nitro: { hooks: { compiled() { whyIsNodeRunning() setTimeout(() => process.exit(0), 0) } } } })`

**Vite:**

`import whyIsNodeRunning from 'why-is-node-running' export default defineConfig({ plugins: [ { name: 'diagnose-hanging-build', apply: 'build', closeBundle() { whyIsNodeRunning() setTimeout(() => process.exit(0), 0) } } ] })`

Deploy once and check your build logs. The diagnostic output will name the file or module keeping the process alive. It's almost always one of:

- A third-party plugin or module doing background work (analytics, error reporting, image uploads, telemetry).
  
- A piece of your own server code that opens a connection or starts a timer at module load.
  

## Step 3: Fix the root cause

Based on what step 2 surfaced:

- **A third-party module with a config option:** look for a setting like `telemetry: false`, `enabled: false` in production, or similar. Disable the background behavior in your build config.
  
- **A third-party module with no config option:** keep the workaround from step 1 in place and file an issue on the module's repo. The diagnostic output from step 2 is exactly what their maintainers need.
  
- **Your own code:** clean up the resource (clear the timer, close the connection, finish the pending task) before the build hook runs.
  

## Quick check if you've recently made changes

If your deployments worked until recently and you're not sure why this started, compare your last working commit to the broken one and look at:

- Your framework config file (`nuxt.config.*`, `vite.config.*`, etc.)
  
- New or upgraded packages in `package.json`
  
- Any new server middleware, plugins, or integrations (especially analytics, monitoring, or error reporting)
  

A newly added package is the most common cause.

---

[View full KB sitemap](/kb/sitemap.md)
