Skip to Content

Knowledge Base Nitro

How to ship a Nitro app on Vercel

Deploy a Nitro app to Vercel with zero configuration. Learn how to ship from a template, the Vercel CLI, or Git, and configure ISR, cron jobs, Vercel Queues, per-route function settings, and Observability.

Content Engineer

Prerequisites

On Vercel, you can deploy a Nitro app with zero configuration: your server routes become Vercel Functions running on Fluid compute, and you get preview deployments, observability, and Vercel Firewall without extra setup.

7 min read

7 Jun 2026

Before you begin, make sure you have:

This guide walks you through deploying a Nitro app to Vercel from a template, the Vercel CLI, or a Git repository, and configuring features such as Incremental Static Regeneration, cron jobs, queues, and observability.

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


How it works

When you deploy a Nitro app, Vercel detects the framework and builds it for the Vercel runtime. Nitro compiles your server routes into Vercel Functions, which run on Fluid compute by default. Your app scales with traffic, and you pay only for the compute your functions use, not for idle time.

Because Vercel ships zero-configuration detection for Nitro, you don't set a build command or output directory. Vercel reads your project, identifies the framework, and applies the correct build settings.


Deploy your Nitro app

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


Option 1: Deploy from a template

The fastest way to ship a Nitro app is to start from a template. Browse the Nitro templates gallery, pick a starter, and deploy it. Vercel clones the template to your Git provider, creates a project, and deploys it with zero configuration.

Templates to start from include:


Option 2: Start a new project with the Vercel CLI

To scaffold a new Nitro project locally, use the Vercel CLI init command. It clones Vercel's Nitro example into a folder named nitro.

  1. Create the project:

    vercel init nitro
  2. Install dependencies:

    cd nitro

    npminstall

  3. Develop locally at http://localhost:3000:

    npm run dev
  4. Create a preview deployment. The first run creates a Vercel project link:

    vercel
  5. Promote your changes to production:

    vercel --prod

Option 3: Deploy an existing Nitro app

If you already have a Nitro 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 Nitro 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:

vercel link

vercel env pull

nitro package, which replaced nitropack). New projects from a template or the Vercel CLI already use v3. If you're bringing an existing app, upgrade to v3 first using the migration guide, or adjust the imports to nitropack/config for nitropack v2.



Use Vercel features with Nitro

After your app is deployed, you can configure Vercel features directly from your Nitro config. The examples below import defineNitroConfig from nitro/config; import { defineConfig } from "nitro" works too.


Server routes run as Vercel Functions

Each Nitro server route automatically becomes a  Vercel Function. These functions use Fluid compute by default, which runs multiple requests concurrently within a single instance to reduce cold starts and I/O-bound work costs, such as API calls and database queries. You don't configure anything to get this behavior.

Cache responses with Incremental Static Regeneration (ISR)

ISR serves cached responses and regenerates them in the background, so you get static performance for dynamic content. Enable it per route with the isr route rule:


isr:{

routeRules:{

"/products/**":{

allowQuery:["q"],

import{ defineNitroConfig }from"nitro/config";

},

});

},

expiration:60,

exportdefaultdefineNitroConfig({

passQuery:true,

By default, each unique query value is cached separately. Set allowQuery to an empty array to ignore query parameters for caching, or list specific parameters to cache only those. Query parameters aren't passed to your route handler unless you set passQuery: true. The isr rule accepts these options:

Option

expiration

number | false

number

Description
Default
Type
string[]

allowQuery

Expose the response body for error status codes.

false
undefined
exposeErrBody

passQuery

Group number for the asset. Assets in the same group revalidate together.

boolean
false
false
boolean

To purge the cache for a route on demand, set a bypass token and send a revalidation request:

  1. Generate a secret and store it as an environment variable such as VERCEL_BYPASS_TOKEN:

    openssl rand -base6432

  2. Reference the secret in your config:

    import{ defineNitroConfig }from"nitro/config";

    exportdefaultdefineNitroConfig({

    vercel:{

    config:{

    bypassToken: process.env.VERCEL_BYPASS_TOKEN,

    },

    },

    });
  3. Send a GET or HEAD request to the route with the header x-prerender-revalidate: . Vercel revalidates the cache, and the next request returns a fresh response.

Run scheduled tasks as cron jobs

Nitro converts its scheduledTasks configuration into Vercel Cron Jobs at build time, so you don't write any vercel.json cron configuration. Enable tasks and define your schedules:


exportdefaultdefineNitroConfig({

tasks:true,

experimental:{

import{ defineNitroConfig }from"nitro/config";

We collaborate with trusted, high-quality partners to bring you reliable and top-notch products and services.

},

});

scheduledTasks:{

},

"0 * * * *":["cms:update"],// every hour

"0 0 * * *":["db:cleanup"],// every day at midnight

Process messages with Vercel Queues

To prevent unauthorized access to the cron handler, set a CRON_SECRET environment variable in your project settings. When it's set, Nitro validates the Authorization header on every cron invocation.

Nitro integrates with Vercel Queues to process messages asynchronously. Define your topics in the config, then handle incoming messages with the vercel:queue hook in a Nitro plugin.

Define the topics:


vercel:{

queues:{

triggers:[

exportdefaultdefineNitroConfig({

{ topic:"notifications"},

},

});

],

},

{ topic:"orders", retryAfterSeconds:60, initialDelaySeconds:5},

import{ defineNitroConfig }from"nitro/config";

Send messages with the @vercel/queue package:


});

});

console.log(`[${metadata.topicName}] ${metadata.messageId}:`, message);

exportdefaultdefineEventHandler(async(event)=>{

exportdefaultdefineNitroPlugin((nitro)=>{

nitro.hooks.hook("vercel:queue",({ message, metadata, send })=>{

});

const order =await event.req.json();

return{ messageId };

import{ send }from"@vercel/queue";

const{ messageId }=awaitsend("orders", order);

Proxy requests at the CDN

Queues also work in nitro dev: send() delivers messages straight to your hook, so you can iterate without deploying. Run vercel link and vercel env pull first so the SDK can authenticate.

Nitro optimizes proxy route rules by generating CDN-level rewrites at build time. Matching requests are proxied through Vercel's CDN without invoking a function, thereby reducing latency and costs.


routeRules:{

"/api/**":{

exportdefaultdefineNitroConfig({

});

},

proxy:"https://api.example.com/**",

},

A proxy rule moves to a CDN rewrite when the target is an external URL (starting with http:// or https://) and the rule sets no advanced ProxyOptions. If you use options such as headers, forwardHeaders, fetchOptions, cookie rewriting, or onResponse, Nitro keeps the proxy at runtime inside the function instead.


Set per-route function configuration

Use vercel.functionRules to override function settings for specific routes. Each key is a route pattern, and its value merges with your base vercel.functions config. Array values like regions replace the base array rather than merging with it.

vercel:{


functionRules:{

},

maxDuration:800,

memory:4096,

"/api/heavy-computation":{

import{ defineNitroConfig }from"nitro/config";

},

});

},

"/api/regional":{

exportdefaultdefineNitroConfig({

regions:["lhr1","cdg1"],

Use the Bun runtime

Route patterns support wildcards, so /api/slow/** matches every route under /api/slow/. This is useful when certain routes need different resource limits, regions, or features like Vercel Queues triggers.

Nitro runs your functions on Node.js by default. To use Bun instead, set the runtime in vercel.functions:


vercel:{


},

});

functions:{

},

runtime:"bun1.x",

import{ defineNitroConfig }from"nitro/config";

{

}

"bunVersion":"1.x"

exportdefaultdefineNitroConfig({

"$schema":"https://openapi.vercel.sh/vercel.json",

Best practices

Monitor performance with Observability


});

exportdefaultdefineNitroConfig({

Vercel Observability breaks down function performance by route, so you can find slow paths and optimization opportunities. Nitro generates the routing hints these insights need. Set a compatibility date of 2025-07-15 or later to turn this on:

import{ defineNitroConfig }from"nitro/config";

compatibilityDate:"2025-07-15",// or "latest"

Put API routes in routes/api

Nitro's top-level /api directory isn't compatible with Vercel. Put your API handlers in routes/api/ instead so they deploy correctly.

Configure Nuxt under the nitro key

Nuxt is built on Nitro, so if you're using Nuxt, place these options under the nitro key in nuxt.config.ts:


},

nitro:{

routeRules:{

isr:{ expiration:60},

"/products/**":{

},

});

},

Resources and next steps

exportdefaultdefineNuxtConfig({