Skip to content

How to ship a NestJS app on Vercel

Deploy a NestJS app to Vercel with zero configuration. Learn how to ship from a template, the Nest CLI, or Git, and configure response streaming, middleware, cron jobs, and Observability.

7 min read
Last updated June 15, 2026

NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications with TypeScript. It gives you an opinionated architecture built around modules, controllers, and providers, with first-class support for dependency injection, guards, interceptors, and pipes.

On Vercel, you can deploy a NestJS app with zero configuration: your application runs as a single Vercel Function on Fluid compute, and you get response streaming, preview deployments, Instant Rollback, and observability without extra setup.

This guide walks you through deploying a NestJS app to Vercel from a template, the Nest CLI, or a Git repository, then configuring features such as streaming, middleware, cron jobs, and observability.

Before you begin, make sure you have:

  • A Vercel account
  • Node.js 20+ and a package manager (e.g., npm)
  • An existing NestJS project, or a new one created from the NestJS on Vercel template or the Nest CLI
  • A Git repository on GitHub, GitLab, or Bitbucket (if you want Git-based deployments)
  • Vercel CLI installed (npm i -g vercel)

When you deploy a NestJS app, Vercel detects the framework and builds it for the Vercel runtime. Your application becomes a single Vercel Function that runs on Fluid compute by default, so it scales with traffic and you pay only for the compute your function uses, not for idle time.

Because Vercel ships zero-configuration detection for NestJS, you don't set a build command or output directory. Vercel reads your project, finds your server entry point, compiles it, and applies the correct build settings.

You can ship a NestJS app to Vercel in three ways. Choose the one that fits where your code lives today.

The fastest way to ship a NestJS app is to start from the NestJS on Vercel template, a ready-to-deploy NestJS API that builds with zero configuration. When you deploy it, Vercel clones the template to your Git provider, creates a project, and deploys it.

To scaffold a new NestJS project locally, use the Nest CLI. It generates a project with the standard src/main.ts entry point that Vercel recognizes out of the box.

  1. Install the Nest CLI and create the project:
    Terminal
    npm i -g @nestjs/cli
    nest new my-nest-app
  2. Move into the project:
    Terminal
    cd my-nest-app
  3. Develop locally with the Vercel CLI, so your app runs the same way it does in production:
    Terminal
    vercel dev
  4. Create a preview deployment. The first run creates a Vercel project link:
    Terminal
    vercel
  5. Promote your deployment to production:
    Terminal
    vercel --prod

If you already have a NestJS app, deploy it from Git or from the command line.

From Git: Push your project to GitHub, GitLab, or Bitbucket, then import it at vercel.com/new. Vercel detects NestJS automatically and deploys it with zero configuration.

From the CLI: From your project's root directory, run vercel to create a preview deployment, then vercel --prod to go live. To pull project settings and environment variables for local development, run:

Terminal
vercel link
vercel env pull

For Vercel to detect your app, use a recognized server entry point. Name your entry file main, app, index, or server (with a .ts, .js, or related extension) at your project root or under src/. The default Nest CLI layout already uses src/main.ts, which Vercel recognizes:

src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

Keep the conventional bootstrap() function that calls app.listen(). Vercel uses it to build and serve your app as a Vercel Function, so you don't change how your NestJS app starts.

After your app is deployed, you can layer Vercel features onto it. Some work automatically, and others take a few lines of code or configuration.

When you deploy a NestJS app, Vercel turns the whole application into a single Vercel Function. Every incoming request goes to that function, and NestJS's router matches the path to the right controller, so your controllers, guards, interceptors, and exception filters all run inside the function.

This function uses Fluid compute by default, which runs multiple requests concurrently within a single instance to reduce cold starts and the cost of I/O-bound work such as API calls and database queries. Because a NestJS app pays an initialization cost to build its dependency-injection container, reusing a warm instance across requests keeps that cost off your hot path. You don't configure anything to get this behavior.

Vercel Functions support streaming, so you can send data to the client as you produce it instead of waiting for the full response. NestJS streams over server-sent events with the @Sse() decorator: annotate a controller method and return an RxJS Observable that emits MessageEvent objects.

src/events.controller.ts
import { Controller, Sse, MessageEvent } from '@nestjs/common';
import { interval, map, Observable } from 'rxjs';
@Controller()
export class EventsController {
@Sse('events')
events(): Observable<MessageEvent> {
return interval(1000).pipe(map(() => ({ data: { status: 'working' } })));
}
}

NestJS subscribes to the Observable, writes each emitted value to the response in text/event-stream format, and closes the connection when the stream completes or the client disconnects. Streaming pairs well with Fluid compute: while your function waits between emissions, the same instance can serve other requests.

To stream model output, AI SDK works inside a NestJS controller, so you can pipe a streamed result straight to the response. This is useful for chat endpoints and other AI workloads.

NestJS and Vercel each have a layer for running code around requests, and they solve different problems. NestJS middleware, guards, and interceptors run inside your app, after the request reaches your function. Use them for app-level concerns such as logging, authentication, and transforming responses. An interceptor, for example, runs logic before and after the handler:

src/logging.interceptor.ts
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable, tap } from 'rxjs';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
const request = context.switchToHttp().getRequest();
console.log('Request:', request.url);
return next.handle().pipe(tap(() => console.log('Response sent')));
}
}

Vercel Routing Middleware runs at the edge, before the request reaches your NestJS app. Use it for rewrites, redirects, and header changes that should happen before any function runs. The two layers work together, with Routing Middleware shaping the request at the edge and NestJS handling it inside your app.

Vercel Cron Jobs trigger a route on a schedule by sending an HTTP GET request to it. Define a controller route for the task, then register the schedule in vercel.json. On serverless, prefer Vercel Cron Jobs over an in-process scheduler, because your function doesn't run continuously between requests.

Define the route:

src/cron.controller.ts
import {
Controller,
Get,
Headers,
UnauthorizedException,
} from '@nestjs/common';
@Controller()
export class CronController {
@Get('api/cron/cleanup')
cleanup(@Headers('authorization') authorization?: string) {
if (authorization !== `Bearer ${process.env.CRON_SECRET}`) {
throw new UnauthorizedException();
}
// Run your scheduled work here
return { ok: true };
}
}

Register the schedule:

vercel.json
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"crons": [{ "path": "/api/cron/cleanup", "schedule": "0 0 * * *" }]
}

Vercel runs cron jobs only on production deployments. To stop anyone else from calling the route, set a CRON_SECRET environment variable in your project settings. Vercel sends it as a Bearer token in the Authorization header on every cron invocation, and your handler compares it before running the task.

Vercel Observability tracks your deployed function automatically, with no setup. Open the Observability page in your project to see invocation counts, error rates, and duration for your NestJS app, along with the requests your function makes to external APIs. On Observability Plus, you also get longer retention and a latency breakdown by route.

Vercel finds your NestJS app by looking for a server entry point at a fixed set of locations: main, app, index, or server (with a .ts, .js, or related extension) at your project root or under src/. The default Nest CLI layout uses src/main.ts, so a standard project works without changes. Keep the conventional bootstrap() function that calls app.listen(), and let Vercel handle the server lifecycle:

src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

Run vercel dev for local development instead of nest start. It serves your app the same way production does, using your compiled entry point, so the behavior you test locally matches what you deploy. This also lets you exercise features such as cron routes before shipping. Local development with vercel dev requires Vercel CLI 48.4.0 or later.

A NestJS app deploys as one Vercel Function, and Vercel Functions are limited to 250 MB. NestJS projects can pull in large dependency trees, so if a deployment approaches the limit, audit your dependencies and move anything you don't need at runtime into devDependencies.

Was this helpful?

supported.