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.
Overview
The Build Output API closely maps to the Vercel product features in a logical and understandable 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.jsonSchema (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.jsonThe 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.jsonThe 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 | Path to an Edge Runtime function 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.jsonThe 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 RemotePattern = {
protocol?: 'http' | 'https';
hostname: string;
port?: string;
pathname?: string;
};
type ImagesConfig = {
sizes: number[];
domains: string[];
remotePatterns?: RemotePattern[];
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. | |
remotePatterns | RemotePattern[] | No | Allowed external patterns that can use Image Optimization. Similar to domains but provides more control with RegExp. |
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": [640, 750, 828, 1080, 1200],
"domains": [],
"minimumCacheTTL": 60,
"formats": ["image/avif", "image/webp"],
"remotePatterns": [{
"protocol": "https",
"hostname": "^via\\.placeholder\\.com$",
"pathname": "^/1280x640/.*$"
}]
}
wildcard
.vercel/output/config.jsonThe 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.jsonThe 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.jsonThe 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": [640, 750, 828, 1080, 1200],
"domains": [],
"minimumCacheTTL": 60,
"formats": ["image/avif", "image/webp"],
"remotePatterns": [{
"protocol": "https",
"hostname": "^via\\.placeholder\\.com$",
"pathname": "^/1280x640/.*$"
}]
}
"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/staticStatic 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/functionsA 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.
Conceptually, you can think of this .func directory as a filesystem mount for a Serverless Function:
the files below the .func directory are included (recursively) and files above the .func directory are not included.
Private files may safely be placed within this directory
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.
A .func directory may be a symlink to another .func directory in cases where you want to have more than one path point to the same underlying Serverless Function.
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.jsonThe .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 specified in the Project Settings. | |
regions | No | List of Vercel Regions where the Serverless Function will be deployed to. | |
supportsWrapper | No | True if a custom runtime has support for Lambda runtime wrappers. |
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/functionsAn 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.jsonThe .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/functionsA 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.jsonThe <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 Runtime function can act as a "middleware" in the HTTP request lifecycle for a Deployment. Middleware is useful for implementing functionality that may be shared by many URL paths in a Project (e.g. authentication), before passing the request through to the underlying resource (such as a page or asset) at that path.
An Edge Middleware is represented on the file system in the same format as an Edge
Function. To use the middleware,
add additional rules in the routes configuration
mapping URLs (using the src property) to the middleware (using the middlewarePath property).
Example
The following example adds a rule that calls the auth middleware for any URL that
starts with /api, before continuing to the underlying resource:
"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 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.