Fastify is a low-overhead Node.js web framework for building APIs. Vercel already provides a native Node.js runtime, 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, 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.
Copy link to headingPrerequisites
- A Vercel account
- Docker Desktop or a running Docker daemon
- Vercel CLI (
npm install -g vercel)
Copy link to headingHow it works
The project is one Fastify application with the following parts:
server.jscreates the server and binds to0.0.0.0on$PORT.Dockerfile.vercelinstalls production dependencies in one stage and runs the service in the final stage.vercel.jsondeclares a container service and rewrites incoming requests to it.- On deployment, Vercel builds the image and runs it as a Vercel Function.
Copy link to headingSteps
Copy link to heading1. Initialize the project
Create and initialize the project:
Set "type": "module" in package.json .
Now, for the HTTP server, create a new file called server.js:
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.
Copy link to heading2. Add Dockerfile.vercel
Create the Dockerfile.vercel file in the project root:
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.
Copy link to heading3. Add vercel.json
Create a vercel.json file to configure your project:
The service selects the container runtime and points to the Dockerfile. The catch-all rewrite sends every public path to the Fastify service.
Copy link to heading4. Run locally
Run the project through Vercel's local container environment:
Use the URL printed by the CLI, usually http://localhost:3000:
Copy link to heading5. Deploy to Vercel
Authenticate and create a production deployment:
For Git-based deployments, push the directory to a repository, import it in Vercel, and keep both configuration files at the configured project root.
Copy link to headingExtend your application
You have deployed a Fastify API in a Node.js container. You can now add routes, plugins, authentication, and external data services.
Copy link to headingEnvironment 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.
Copy link to headingDatabase and storage
The container runs on Vercel Functions, where the file system is not persistent. For persistent workloads, use Vercel Blob for files, a Marketplace Postgres integration for relational data, a Marketplace Redis integration for sessions and caching, and Vercel Global Config for frequently read configuration.
Keep database pools small and create them outside request handlers so a warm instance can reuse connections.
Copy link to headingIterate with preview deployments
A connected Git repository receives a unique Preview Deployment for each branch push or pull request. Run vercel deploy without --prod to create the same disposable environment from the CLI.
Copy link to headingScale automatically with Fluid compute
Vercel Services use 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.
Copy link to headingTroubleshooting
Copy link to headingThe 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.
Copy link to headingThe 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.
Copy link to headingDatabase 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.
Copy link to headingBackground 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 for schedules and Workflow for durable multi-step work. Keep request handlers idempotent.
Copy link to headingNext steps
- Learn how Vercel Services routes traffic between backends and frontends
- Learn how to run Docker on Vercel
- Review the vercel.json reference
- Read the container images documentation for execution limits
- Explore the Vercel Frameworks documentation