Feedback: We would love to hear your thoughts and opinions as you try out this Beta product. Join the conversation on our Build Output API (v3) GitHub discussions board

The Build Output API is a file-system-based specification for a directory structure that can produce a Vercel deployment.

Framework authors can implement this directory structure as the output of their build command, so that the framework may utilize all of the Vercel platform features.

Note: As a beta feature, the Build Output API (v3) requires an Environment Variable named ENABLE_VC_BUILD to be set to 1 in order to enable the feature.

Overview

The Build Output API closely maps to the Vercel product features in a logical and easy-to-understand format.

It is primarily targeted toward authors of web frameworks who would like to utilize all of the Vercel platform features, such as Serverless Functions, Edge Functions, Routing, Caching, etc.

If you are a framework author looking to integrate with Vercel, you can use this reference as a way to understand which files the framework should emit to the .vercel/output directory.

If you are not using a framework and would like to still take advantage of any of the features that those frameworks provide, you can create the .vercel/output directory and populate it according to this specification yourself.

You can find complete examples of Build Output API directories in vercel/examples.

Known Limitations

Native Dependencies: Please keep in mind that when building locally, your build tools will compile native dependencies targeting your machine’s architecture. This will not necessarily match what runs in production on Vercel.

For projects that depend on native binaries, you should build on a host machine running Linux with a x64 CPU architecture, ideally the same as the platform Build Image.

Build Output Configuration

.vercel/output/config.json

Schema (as TypeScript):

type Config = {
  version: 3;
  routes?: Route[];
  images?: ImagesConfig;
  wildcard?: WildcardConfig;
  overrides?: OverrideConfig;
  cache?: string[];
};

Config Types:

The config.json file contains configuration information and metadata for a Deployment. The individual properties are described in greater detail in the sub-sections below.

At a minimum, a config.json file with a "version" property is required.

Supported Properties

version

.vercel/output/config.json

The version property indicates which version of the Build Output API has been implemented. The version described in this document is version 3.

Example

  "version": 3

routes

.vercel/output/config.json

The routes property describes the routing rules that will be applied to the Deployment. It uses the same syntax as the routes property of the vercel.json file.

Routes may be used to point certain URL paths to others on your Deployment, attach response headers to paths, and various other routing-related use-cases.

type Route = Source | Handler;

Source Route

type Source = {
  src: string;
  dest?: string;
  headers?: Record<string, string>;
  methods?: string[];
  continue?: boolean;
  caseSensitive?: boolean;
  check?: boolean;
  status?: number;
  has?: Array<HostHasField | HeaderHasField | CookieHasField | QueryHasField>;
  missing?: Array<
    HostHasField | HeaderHasField | CookieHasField | QueryHasField
  >;
  locale?: Locale;
  middlewarePath?: string;
};
Key
Required
Description
src
Yes
A PCRE-compatible regular expression that matches each incoming pathname (excluding querystring).
dest
No
A destination pathname or full URL, including querystring, with the ability to embed capture groups as $1, $2, or named capture value $name.
headers
No
A set of headers to apply for responses.
methods
No
A set of HTTP method types. If no method is provided, requests with any HTTP method will be a candidate for the route.
continue
No
A boolean to change matching behavior. If true, routing will continue even when the src is matched.
caseSensitive
No
Specifies whether or not the route src should match with case sensitivity.
check
No
If true, the route triggers handle: 'filesystem' and handle: 'rewrite'
status
No
A status code to respond with. Can be used in tandem with Location: header to implement redirects.
has
Array<HostHasField | HeaderHasField | CookieHasField | QueryHasField>
No
Conditions of the HTTP request that must exist to apply the route.
missing
Array<HostHasField | HeaderHasField | CookieHasField | QueryHasField>
No
Conditions of the HTTP request that must NOT exist to match the route.
locale
Locale
No
Conditions of the Locale of the requester that will redirect the browser to different routes.
middlewarePath
No
A middleware name that matches an Edge Function path that should be invoked as middleware.
Source Route: Locale
type Locale = {
  redirect?: Record<string, string>;
  cookie?: string;
};
Key
Required
Description
redirect
Yes
An object of keys that represent locales to check for (en, fr, etc.) that map to routes to redirect to (/, /fr, etc.).
cookie
No
Cookie name that can override the Accept-Language header for determing the current locale.
Source Route: HostHasField
type HostHasField = {
  type: 'host';
  value: string;
};
Key
Required
Description
type
"host"
Yes
Determines the HasField type.
value
Yes
Host name that must match the request URL's host to cause this route to match.
Source Route: HeaderHasField
type HeaderHasField = {
  type: 'header';
  key: string;
  value?: string;
};
Key
Required
Description
type
"header"
Yes
Determines the HasField type.
key
Yes
Header name that must exist on the request for this route to match.
value
No
Header value (or regex) that must match for this route to match.
Source Route: CookieHasField
type CookieHasField = {
  type: 'cookie';
  key: string;
  value?: string;
};
Key
Required
Description
type
"cookie"
Yes
Determines the HasField type.
key
Yes
Cookie name that must exist on the request for this route to match.
value
No
Cookie value (or regex) that must match for this route to match.
Source Route: QueryHasField
type QueryHasField = {
  type: 'query';
  key: string;
  value?: string;
};
Key
Required
Description
type
"query"
Yes
Determines the HasField type.
key
Yes
Querystring key to look for.
value
No
Querystring value (or regex) that must match for this route to match.

Handler Route

The routing system has multiple phases. The handle value indicates the start of a phase. All following routes are only checked in that phase.

type HandleValue =
  | 'rewrite'
  | 'filesystem' // check matches after the filesystem misses
  | 'resource'
  | 'miss' // check matches after every filesystem miss
  | 'hit'
  | 'error'; //  check matches after error (500, 404, etc.)

type Handler = {
  handle: HandleValue;
  src?: string;
  dest?: string;
  status?: number;
};
Key
Required
Description
handle
HandleValue
Yes
The phase of routing when all subsequent routes should apply.
src
No
A PCRE-compatible regular expression that matches each incoming pathname (excluding querystring).
dest
No
A destination pathname or full URL, including querystring, with the ability to embed capture groups as $1, $2.
status
No
A status code to respond with. Can be used in tandem with Location: header to implement redirects.

Example

The following example shows a routing rule that will cause the /redirect path to perform an HTTP redirect to an external URL:

  "routes": [
    {
      "src": "/redirect",
      "status": 308,
      "headers": { "Location": "https://example.com/" }
    }
  ]

images

.vercel/output/config.json

The images property describes the image optimization configuration when utilizing Vercel's native Image Optimization feature, which automatically adjusts the size and quality of your images, to make sure they are served to your visitors as quickly as possible.

type ImageFormat = 'image/avif' | 'image/webp';

type ImagesConfig = {
  sizes: number[];
  domains: string[];
  minimumCacheTTL?: number; // seconds
  formats?: ImageFormat[];
  dangerouslyAllowSVG?: boolean;
  contentSecurityPolicy?: string;
};
Key
Required
Description
sizes
Yes
Supported image widths.
domains
Yes
Allowed external domains that can use Image Optimization. Leave empty for only allowing the deployment domain to use Image Optimization.
minimumCacheTTL
No
Cache duration (in seconds) for the optimized images.
formats
ImageFormat[]
No
Supported output image formats
dangerouslyAllowSVG
No
Allow SVG input image URLs. This is disabled by default for security purposes.
contentSecurityPolicy
No
Change the Content Security Policy of the optimized images.

Example

The following example shows an image optimization configuration that specifies allowed image size dimensions, external domains, caching lifetime and file formats:

  "images": {
    "sizes": [256, 384],
    "domains": ["external-site.com"],
    "minimumCacheTTL": 60,
    "formats": ["image/webp", "image/avif"]
  }

wildcard

.vercel/output/config.json

The wildcard property relates to Vercel's Internationalization feature. The way it works is the domain names listed in this array are mapped to the $wildcard routing variable, which can be referenced by the routes configuration.

Each of the domain names specified in the wildcard configuration will need to be assigned as Production Domains in the Project Settings.

type WildCard = {
  domain: string;
  value: string;
};

type WildcardConfig = Array<WildCard>;

Supported Properties

Objects contained within the wildcard configuration support the following properties:

Key
Required
Description
domain
Yes
The domain name to match for this wildcard configuration.
value
Yes
The value of the $wildcard match that will be available for routes to utilize.

Example

The following example shows a wildcard configuration where the matching domain name will be served the localized version of the blog post HTML file:

  "wildcard": [
    {
      "domain": "example.com",
      "value": "en-US"
    },
    {
      "domain": "example.nl",
      "value": "nl-NL"
    },
    {
      "domain": "example.fr",
      "value": "fr"
    }
  ],
  "routes": [
    { "src": "/blog", "dest": "/blog.$wildcard.html" }
  ]

overrides

.vercel/output/config.json

The overrides property allows for overriding the output of one or more static files contained within the .vercel/output/static directory.

The main use-cases are to override the Content-Type header that will be served for a static file, and/or to serve a static file in the Vercel Deployment from a different URL path than how it is stored on the file system.

type Override = {
  path?: string;
  contentType?: string;
};

type OverrideConfig = Record<string, Override>;

Supported Properties

Objects contained within the overrides configuration support the following properties:

Key
Required
Description
path
No
The URL path where the static file will be accessible from.
contentType
No
The value of the Content-Type HTTP response header that will be served with the static file.

Example

The following example shows an override configuration where an HTML file can be accessed without the .html file extension:

  "overrides": {
    "blog.html": {
      "path": "blog"
    }
  }

cache

.vercel/output/config.json

The cache property is an array of file paths and/or glob patterns that should be re-populated within the build sandbox upon subsequent Deployments.

Note that this property is only relevant when Vercel is building a Project from source code, meaning it is not relevant when building locally or when creating a Deployment from "prebuilt" build artifacts.

type Cache = string[];

Example

  "cache": [
    ".cache/**",
    "node_modules/**"
  ]

Full Example

{
  "version": 3,
  "routes": [
    {
      "src": "/redirect",
      "status": 308,
      "headers": { "Location": "https://example.com/" }
    },
    {
      "src": "/blog",
      "dest": "/blog.$wildcard.html"
    }
  ],
  "images": {
    "sizes": [256, 384],
    "domains": ["external-site.com"],
    "minimumCacheTTL": 60,
    "formats": ["image/webp", "image/avif"]
  },
  "wildcard": [
    {
      "domain": "example.com",
      "value": "en-US"
    },
    {
      "domain": "example.nl",
      "value": "nl-NL"
    },
    {
      "domain": "example.fr",
      "value": "fr"
    }
  ],
  "overrides": {
    "blog.html": {
      "path": "blog"
    }
  },
  "cache": [".cache/**", "node_modules/**"]
}

Vercel Primitives

The following directories, code files, and configuration files represent all Vercel platform primitives. These primitives are the "building blocks" that make up a Vercel Deployment.

Files outside of these directories are ignored and will not be served to visitors.

Static Files

.vercel/output/static

Static files that are publicly accessible from the Deployment URL should be placed in the .vercel/output/static directory. These files are served via the Vercel Edge Network.

Files placed within this directory will be made available at the root (/) of the Deployment URL and neither their contents, nor their file name or extension will be modified in any way. Sub directories within static are also retained in the URL, and are appended before the file name.

Configuration

There is no standalone configuration file that relates to static files.

However, certain properties of static files (such as the Content-Type response header) can be modified by utilizing the overrides property of the config.json file.

File System Example

The following example shows static files placed into the .vercel/output/static directory:

Serverless Functions

.vercel/output/functions

A Serverless Function is represented on the file system as a directory with a .func suffix on the name, contained within the .vercel/output/functions directory.

All files inside of a given .func directory are included inside the Serverless Function execution environment. Private files may safely be placed within these directories because they will not be directly accessible to end-users. However, they can be referenced by code that will be executed by the Serverless Function.

Additionally, a configuration file named .vc-config.json must be included within the .func directory, which contains information about how Vercel should construct the Serverless Function.

The .func suffix on the directory name is not included as part of the URL path of Serverless Function on the Deployment. For example, a directory located at .vercel/output/functions/api/posts.func will be accessible at the URL path /api/posts of the Deployment.

Configuration

.vercel/output/functions/<name>.func/.vc-config.json

The .vc-config.json configuration file contains information related to how the Serverless Function will be created by Vercel.

Base Config

type ServerlessFunctionConfig = {
  handler: string;
  runtime: string;
  memory?: number;
  maxDuration?: number;
  environment: Record<string, string>[];
  allowQuery?: string[];
  regions?: string[];
};
Key
Required
Description
runtime
Yes
Specifies which "runtime" will be used to execute the Serverless Function.
handler
Yes
Indicates the initial file where code will be executed for the Serverless Function.
memory
No
Amount of memory (RAM in MB) that will be allocated to the Serverless Function.
maxDuration
No
Maximum execution duration (in seconds) that will be allowed for the Serverless Function.
environment
No
Map of additional environment variables that will be available to the Serverless Function, in addition to the env vars specifed in the Project Settings.
regions
No
List of Vercel Regions where the Serverless Function will be deployed to.

Node.js Config

This extends the Base Config for Node.js Serverless Functions.

type NodejsServerlessFunctionConfig = ServerlessFunctionConfig & {
  launcherType: 'Nodejs';
  shouldAddHelpers?: boolean; // default: false
  shouldAddSourceMapSupport?: boolean; // default: false
};
Key
Required
Description
launcherType
"Nodejs"
Yes
Specifies which launcher to use. Currently only "Nodejs" is supported.
shouldAddHelpers
No
Enables request and response helpers methods.
shouldAddSourcemapSupport
No
Enables source map generation.
awsLambdaHandler
No
AWS Handler Value for when the serverless function uses AWS Lambda syntax.

Config Example

This is what the .vc-config.json configuration file could look like in a real scenario:

{
  "runtime": "nodejs16.x",
  "handler": "serve.js",
  "maxDuration": 3,
  "launcherType": "Nodejs",
  "shouldAddHelpers": true,
  "shouldAddSourcemapSupport": true
}

File System Example

The following example shows a directory structure where the Serverless Function will be accessible at the /serverless URL path of the Deployment:

Edge Functions

.vercel/output/functions

An Edge Function is represented on the file system as a directory with a .func suffix on the name, contained within the .vercel/output/functions directory.

JavaScript source files placed within the .func directory are bundled at build-time. A WASM file may also be placed in this directory for an Edge Function to utilize.

Configuration

.vercel/output/functions/<name>.func/.vc-config.json

The .vc-config.json configuration file contains information related to how the Edge Function will be created by Vercel.

type EdgeFunctionConfig = {
  runtime: 'edge';
  entrypoint: string;
  envVarsInUse?: string[];
};
Key
Required
Description
runtime
Yes
The runtime: "edge" property is required to indicate that this directory represents an Edge Function.
entrypoint
Yes
Indicates the initial file where code will be executed for the Edge Function.
envVarsInUse
No
List of environment variable names that will be available for the Edge Function to utilize.

Config Example

This is what the .vc-config.json configuration file could look like in a real scenario:

{
  "runtime": "edge",
  "entrypoint": "index.js",
  "envVarsInUse": ["DATABASE_API_KEY"]
}

File System Example

The following example shows a directory structure where the Edge Function will be accessible at the /edge URL path of the Deployment:

Prerender Functions

.vercel/output/functions

A Prerender asset is a Serverless Function that will be cached by the Vercel Edge Network in the same way as a static file. This concept is also known as Incremental Static Regeneration.

On the file system, a Prerender is represented in the same way as a Serverless Function, with an additional configuration file that describes the cache invalidation rules for the Prerender asset.

An optional "fallback" static file can also be specified, which will be served when there is no cached version available.

Configuration

.vercel/output/functions/<name>.prerender-config.json

The <name>.prerender-config.json configuration file contains information related to how the Edge Function will be created by Vercel.

type PrerenderFunctionConfig = {
  expiration: number | false;
  group?: number;
  bypassToken?: string;
  fallback?: string;
  allowQuery?: string[];
};
Key
Required
Description
expiration
Yes
Expiration time (in seconds) before the cached asset will be re-generated by invoking the Serverless Function. Setting the value to false means it will never expire.
group
No
Option group number of the asset. Prerender assets with the same group number will all be re-validated at the same time.
bypassToken
No
Random token that can be provided in the URL to bypass the cached version of the asset. Useful for Preview Mode.
fallback
No
Name of the optional fallback file relative to the configuration file.
allowQuery
No
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

Fallback Static File

.vercel/output/functions/<name>.prerender-fallback.<ext>

A Prerender asset may also include a static "fallback" version that is generated at build-time. The fallback file will be served by Vercel while there is not yet a cached version that was generated during runtime.

When the fallback file is served, the Serverless Function will also be invoked "out-of-band" to re-generate a new version of the asset that will be cached and served for future HTTP requests.

Config Example

This is what an example.prerender-config.json file could look like in a real scenario:

{
  "expiration": 60,
  "group": 1,
  "bypassToken": "03326da8bea31b919fa3a31c85747ddc",
  "fallback": "example.prerender-fallback.html",
  "allowQuery": ["id"]
}

File System Example

The following example shows a directory structure where the Prerender will be accessible at the /blog URL path of the Deployment:

Features

This section describes how to implement common Vercel platform features through the Build Output API through a combination of platform primitives, configuration and helper functions.

High-Level Routing

The vercel.json file supports an easier-to-use syntax for routing through properties like rewrites, headers, etc. However, the config.json "routes" property supports a lower-level syntax.

The getTransformedRoutes() function from the @vercel/routing-utils npm package can be used to convert this higher-level syntax into the lower-level format that is supported by the Build Output API. For example:

import { writeFileSync } from 'fs';
import { getTransformedRoutes } from '@vercel/routing-utils';

const { routes } = getTransformedRoutes({
  trailingSlash: false,
  redirects: [
    { source: '/me', destination: '/profile.html' },
    { source: '/view-source', destination: 'https://github.com/vercel/vercel' },
  ],
});

const config = {
  version: 3,
  routes,
};
writeFileSync('.vercel/output/config.json', JSON.stringify(config));

cleanUrls

The cleanUrls: true routing feature is a special case because, in addition to the routes generated with the helper function above, it also requires that the static HTML files have their .html suffix removed.

This can be achieved by utilizing the "overrides" property in the config.json file:

import { writeFileSync } from 'fs';
import { getTransformedRoutes } from '@vercel/routing-utils';

const { routes } = getTransformedRoutes({
  cleanUrls: true,
});

const config = {
  version: 3,
  routes,
  overrides: {
    'blog.html': {
      path: 'blog',
    },
  },
};
writeFileSync('.vercel/output/config.json', JSON.stringify(config));

Edge Middleware

An Edge Function can act as a "middleware" of the HTTP request lifecycle for a Deployment. Middleware are useful for implementing functionality common to many endpoints in an Project, such as authentication or specialized routing logic, before "passing through" the request to complete the request lifecycle.

An Edge Middleware is represented on the file system as a standard Edge Function, with an additional routing rule in the routes configuration that specifies the URL path(s) where the edge function should be invoked.

Example

The following example shows adding a routing rule that specifies name of an Edge Function as the middlewarePath property. The edge function will be invoked for any HTTP request under the /api prefix, before continuing to serve the underlying asset:

  "routes": [
    {
      "src": "/api/(.*)",
      "middlewarePath": "auth",
      "continue": true
    }
  ]

Preview Mode

When using Prerender Functions, you may want to implement "Preview Mode" which would allow you to bypass the caching aspect of prerender functions. For example, while writing draft blog posts before they are ready to be published.

To implement this, the bypassToken of the <name>.prerender-config.json file should be set to a randomized string that you generate at build-time. This string should not be exposed to users / the client-side, except under authenticated circumstances.

To enable "Preview Mode", a cookie with the name __prerender_bypass needs to be set (i.e. by a Serverless Function) with the value of the bypassToken. When the Prerender Function endpoint is accessed while the cookie is set, then "Preview Mode" will be activated, bypassing any caching that Vercel would normally provide when not in preview mode.

On-Demand Incremental Static Regeneration (ISR)

When using Prerender Functions, you may want to implement "On-Demand Incremental Static Regeneration (ISR)" which would allow you to invalidate the cache at any time.

To implement this, the bypassToken of the <name>.prerender-config.json file should be set to a randomized string that you generate at build-time. This string should not be exposed to users / the client-side, except under authenticated circumstances.

To trigger "On-Demand Incremental Static Regeneration (ISR)" and revalidate a path to a Prerender Function, make a GET (no other method) 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.