---
title: Deploy Node.js with Fastify on Vercel with Docker
description: Build a Node.js application with Fastify and Docker, then deploy it to Vercel Functions. Learn how to configure environment variables, managed storage, and preview deployments for your project.
url: /kb/guide/deploy-nodejs-on-vercel-with-docker
canonical_url: "https://vercel.com/kb/guide/deploy-nodejs-on-vercel-with-docker"
published: 2026-08-11
last_updated: 2026-08-11
authors: Anshuman Bhardwaj
related:
  - /docs/frameworks/backend/fastify
  - /docs/container-registry
  - /docs/cli
  - /docs/vercel-blob
  - /docs/global-config
  - /docs/deployments/environments
  - /docs/services
  - /docs/fluid-compute
  - /docs/cron-jobs
  - /docs/workflows
  - /kb/guide/docker
  - /docs/project-configuration/vercel-json
  - /docs/functions/container-images
  - /docs/frameworks
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

Fastify is a low-overhead Node.js web framework for building APIs. Vercel already provides a [native Node.js runtime](https://vercel.com/docs/frameworks/backend/fastify), but a container is useful when your application depends on a specific Linux distribution, operating system packages, or an existing container build. Add a `Dockerfile.vercel` and set the service `runtime` to `container`. Vercel builds the image, stores it in the [Vercel Container Registry](https://vercel.com/docs/container-registry), and serves it from a Function that autoscales with traffic and scales to zero when idle.

This guide deploys a minimal Fastify API, binds it to Vercel’s `PORT`, and explains how to use durable external storage instead of the container file system.

## Prerequisites

- A [Vercel account](https://vercel.com)
  
- Docker Desktop or a running Docker daemon
  
- [Vercel CLI](https://vercel.com/docs/cli) (`npm install -g vercel`)
  

## How it works

The project is one Fastify application with the following parts:

- `server.js` creates the server and binds to `0.0.0.0` on `$PORT`.
  
- `Dockerfile.vercel` installs production dependencies in one stage and runs the service in the final stage.
  
- `vercel.json` declares a container service and rewrites incoming requests to it.
  
- On deployment, Vercel builds the image and runs it as a Vercel Function.
  

## Steps

### 1\. Initialize the project

Create and initialize the project:

```bash
mkdir vercel-docker-node
cd vercel-docker-node
npm init -y
npm install fastify
```

Set `"type": "module"` in `package.json` .

```javascript
{
  "name": "vercel-node-docker",
  "private": true,
  "type": "module",
  "scripts": { "start": "node server.js" },
  "dependencies": { "fastify": "^5.6.1" }
}
```

Now, for the HTTP server, create a new file called `server.js`:

```javascript
import Fastify from "fastify";

const app = Fastify({ logger: true });
app.get("/", async () => ({ message: "Hello from Node.js on Vercel" }));
app.get("/health", async () => ({ status: "ok" }));

const port = Number.parseInt(process.env.PORT ?? "80", 10);
await app.listen({ host: "0.0.0.0", port });

process.on("SIGTERM", async () => {
  const timer = setTimeout(() => process.exit(1), 25_000).unref();
  await app.close();
  clearTimeout(timer);
  process.exit(0);
});
```

The server must bind to `0.0.0.0`, not `localhost`, and read `PORT`. The fallback to port 80 matches Vercel's default container port.

### 2\. Add `Dockerfile.vercel`

Create the `Dockerfile.vercel` file in the project root:

```dockerfile
FROM node:24-alpine AS dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev

FROM node:24-alpine
WORKDIR /app
COPY --from=dependencies /app/node_modules ./node_modules
COPY package.json server.js ./
ENV NODE_ENV=production PORT=80
USER node
CMD ["node", "server.js"]
```

Copying the manifests before the application code lets Docker reuse the dependency layer. The final stage contains Node.js and production dependencies, excludes npm's build cache, and runs as the image's non-root `node` user.

### 3\. Add `vercel.json`

Create a `vercel.json` file to configure your project:

```json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "services": {
    "api": {
      "root": ".",
      "entrypoint": "Dockerfile.vercel",
      "runtime": "container"
    }
  },
  "rewrites": [
    { "source": "/(.*)", "destination": { "service": "api" } }
  ]
}
```

The service selects the container runtime and points to the Dockerfile. The catch-all rewrite sends every public path to the Fastify service.

### 4\. Run locally

Run the project through Vercel's local container environment:

```bash
vercel dev -L
```

Use the URL printed by the CLI, usually `http://localhost:3000`:

```bash
curl http://localhost:3000/
curl http://localhost:3000/health
```

### 5\. Deploy to Vercel

Authenticate and create a production deployment:

```bash
vercel login
vercel deploy --prod
```

For Git-based deployments, push the directory to a repository, import it in Vercel, and keep both configuration files at the configured project root.

## Extend your application

You have deployed a Fastify API in a Node.js container. You can now add routes, plugins, authentication, and external data services.

### Environment variables

Add configuration in the project settings or with `vercel env add NAME`. Pull development values locally with `vercel env pull`. Store secrets in environment variables and do not commit them or bake them into the image.

### Database and storage

The container runs on Vercel Functions, where the file system is not persistent. For persistent workloads, use [Vercel Blob](https://vercel.com/docs/vercel-blob) for files, a [Marketplace Postgres integration](https://vercel.com/marketplace/category/storage?category=storage&search=postgres) for relational data, a [Marketplace Redis integration](https://vercel.com/marketplace/category/storage?category=storage&search=redis) for sessions and caching, and [Vercel Global Config](https://vercel.com/docs/global-config) for frequently read configuration.

Keep database pools small and create them outside request handlers so a warm instance can reuse connections.

### Iterate with preview deployments

A connected Git repository receives a unique [Preview Deployment](https://vercel.com/docs/deployments/environments) for each branch push or pull request. Run `vercel deploy` without `--prod` to create the same disposable environment from the CLI.

### Scale automatically with Fluid compute

[Vercel Services](https://vercel.com/docs/services) use [Fluid compute](https://vercel.com/docs/fluid-compute) by default. Instances can process concurrent requests and scale to zero between traffic. Active CPU billing stops while code waits on I/O and when no requests are running; memory and invocation charges still apply.

## Troubleshooting

### The deployment builds but requests return 502

**Cause:** Fastify is listening on `localhost` or a hardcoded port such as 3000 instead of the port Vercel routes to.

**Fix:** Pass `host: "0.0.0.0"` to `listen` and parse `process.env.PORT`, with 80 as the fallback. `EXPOSE` does not configure routing.

### The process exits before requests arrive

**Cause:** The final image is missing `server.js`, production dependencies, or ESM configuration. An unhandled startup rejection also terminates Node.js.

**Fix:** Build locally, run the image with `PORT=8080`, and inspect `vercel logs`. Keep `"type": "module"` in `package.json` when using `import` syntax.

### Database connections increase during traffic spikes

**Cause:** Each scaled instance creates its own pool, and a pool created inside a request handler creates even more connections.

**Fix:** Create one small pool at module scope, use a provider's pooled connection string, and place the database near the Function region.

### Background work stops unexpectedly

**Cause:** Timers, queues, and detached promises assume the Node.js process remains alive after a response. Instances can pause or terminate when idle between requests.

**Fix:** Use [Vercel Cron](https://vercel.com/docs/cron-jobs) for schedules and [Workflow](https://vercel.com/docs/workflows) for durable multi-step work. Keep request handlers idempotent.

## Next steps

- Learn how [Vercel Services](https://vercel.com/docs/services) routes traffic between backends and frontends
  
- Learn how to run [Docker on Vercel](https://vercel.com/kb/guide/docker)
  
- Review the [vercel.json reference](https://vercel.com/docs/project-configuration/vercel-json)
  
- Read the [container images documentation](https://vercel.com/docs/functions/container-images) for execution limits
  
- Explore the [Vercel Frameworks documentation](https://vercel.com/docs/frameworks)