Nitro logoNitro

Vercel

Deploy Nitro apps to Vercel.

Preset: vercel

Read more in Vercel Framework Support.
Integration with this provider is possible with zero configuration.

Getting started

Deploying to Vercel comes with the following features:

And much more. Learn more in the Vercel documentation.

Deploy with Git

Vercel supports Nitro with zero-configuration. Deploy Nitro to Vercel now.

Observability

Nitro (>=2.12) generates routing hints for functions observability insights, providing a detailed view of performance broken down by route.

To enable this feature, ensure you are using a compatibility date of 2025-07-15 or later.

export default defineNitroConfig({
    compatibilityDate: "2025-07-15", // or "latest"
})

Framework integrations can use the ssrRoutes configuration to declare SSR routes. For more information, see #3475.

Bun runtime

Read more in Vercel.

You can use Bun instead of Node.js by specifying the runtime using the vercel.functions key inside nitro.config:

nitro.config.ts
export default defineNitroConfig({
  vercel: {
    functions: {
      runtime: "bun1.x"
    }
  }
})

Alternatively, Nitro also detects Bun automatically if you specify a bunVersion property in your vercel.json:

vercel.json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "bunVersion": "1.x"
}

Queues

Read more in Vercel Queues.

Nitro integrates with Vercel Queues to process messages asynchronously. Define your queue topics in the Nitro config and handle incoming messages with the vercel:queue runtime hook.

nitro.config.ts
export default defineNitroConfig({
  vercel: {
    queues: {
      triggers: [
        // Only `topic` is required
        { topic: "notifications" },
        { topic: "orders", retryAfterSeconds: 60, initialDelaySeconds: 5 },
      ],
    },
  },
});
The @vercel/queue package is required when using queues. Install it in your project with your package manager. Local development requires @vercel/queue v0.2.0 or newer.

Handling messages

Use the vercel:queue hook in a Nitro plugin to process incoming queue messages:

server/plugins/queues.ts
export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook("vercel:queue", ({ message, metadata, send }) => {
    console.log(`[${metadata.topicName}] Message ${metadata.messageId}:`, message);
  });
});

Running tasks from queue messages

You can use queue messages to trigger Nitro tasks:

server/plugins/queues.ts
import { runTask } from "nitropack/runtime";

export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook("vercel:queue", async ({ message, metadata }) => {
    if (metadata.topicName === "orders") {
      await runTask("orders:fulfill", { payload: message });
    }
  });
});

Sending messages

Use the @vercel/queue package directly to send messages to a topic:

server/routes/api/orders.post.ts
import { send } from "@vercel/queue";

export default defineEventHandler(async (event) => {
  const order = await readBody(event);
  const { messageId } = await send("orders", order);
  return { messageId };
});

Local development

Queues work in nitro devsend() delivers messages straight to your vercel:queue hook, so you can iterate without deploying. Pull your Vercel environment first with vercel link and vercel env pull so the SDK can authenticate.

If your hook throws, the message is retried locally. Retries honour retryAfterSeconds from each trigger when set.

Custom build output configuration

You can provide additional build output configuration using vercel.config key inside nitro.config. It will be merged with built-in auto-generated config.

On-Demand incremental static regeneration (ISR)

On-demand revalidation allows you to purge the cache for an ISR route whenever you want, foregoing the time interval required with background revalidation.

To revalidate a page on demand:

  • Create an Environment Variable which will store a revalidation secret
    • You can use the command openssl rand -base64 32 or Generate a Secret to generate a random value.
  • Update your configuration:
    export default defineNitroConfig({
      vercel: {
        config: {
          bypassToken: process.env.VERCEL_BYPASS_TOKEN
        }
      }
    })
    
  • To trigger "On-Demand Incremental Static Regeneration (ISR)" and revalidate a path to a Prerender Function, make a GET or HEAD request to that path with a header of x-prerender-revalidate: bypassToken. When that Prerender Function endpoint is accessed with this header set, the cache will be revalidated. The next request to that function should return a fresh response.

Fine-grained ISR config via route rules

By default, query paramas are ignored by cache.

You can pass an options object to isr route rule to configure caching behavior.

  • expiration: Expiration time (in seconds) before the cached asset will be re-generated by invoking the Serverless Function. Setting the value to false (or isr: true route rule) means it will never expire.
  • group: Group number of the asset. Prerender assets with the same group number will all be re-validated at the same time.
  • allowQuery: List of query string parameter names that will be cached independently.
    • If an empty array, query values are not considered for caching.
    • If undefined each unique query value is cached independently.
    • For wildcard /** route rules, url is always added
  • passQuery: When true, the query string will be present on the request argument passed to the invoked function. The allowQuery filter still applies.
  • exposeErrBody: When true, expose the response body regardless of status code including error status codes. (default false
export default defineNitroConfig({
  routeRules: {
    "/products/**": {
      isr: {
        allowQuery: ["q"],
        passQuery: true,
        exposeErrBody: true
      },
    },
  },
});

Vercel edge functions

Preset: vercel_edge (deprecated)

We recommend migrating to the default Node.js runtime and enabling Fluid compute.