Skew Protection
Skew Protection is available on Enterprise and Pro plans
Those with the owner, admin, member role can access this feature
Version skew occurs when different versions of your application run on client and server, causing application errors and other unexpected behavior. For example, imagine your newest deployment modifies the data structure by adding a required field to a user's profile. Older clients wouldn't expect this new field, leading to errors when they submit it.
Vercel's Skew Protection resolves this problem at the platform and framework layer by using version locking, which ensures client and server use the exact same version. In our example, outdated clients continue to communicate with servers that understand the old data structure, while updated clients use the most recent deployment.


By implementing Skew Protection, you can reduce user-facing errors during new rollouts and boost developer productivity, minimizing concerns about API compatibility across versions.
When Skew Protection is enabled with a supported framework, the framework automatically includes the deployment ID in framework-managed requests from the client. These include:
- Static assets: JavaScript bundles, CSS files, and images loaded by the framework
- Client-side navigations: Route transition data fetches and Server Actions
- Prefetches: Route and data prefetch requests triggered by the framework
The framework attaches the deployment ID as a ?dpl= query parameter or x-deployment-id header, ensuring these requests resolve to the same deployment that served the initial page. The framework doesn't automatically pin custom fetch() calls you make from client components. To pin those, pass the deployment ID yourself using the methods described in supported frameworks.
The framework doesn't pin full-page navigations by default. When the browser makes a top-level document request, such as a hard refresh, entering a URL in the address bar, or opening a link in a new tab, Vercel serves the latest production deployment. If a new deployment went live since the user's last page load, the client detects the version mismatch and triggers a full page reload so the user receives the updated version.
For most applications, this is the ideal behavior. Users get the latest version on their next full-page navigation while their current page stays stable.
However, some applications have long-running sessions where a full page reload would disrupt the user experience. See Extending Skew Protection for long-lived sessions for how to handle these cases.
Projects created after November 19th 2024 using one of the supported frameworks already have Skew Protection enabled by default.
For older projects, you can enable Skew Protection in your project's settings.
- Ensure your project has the Enable access to System Environment Variables setting enabled
- Select the project in the Vercel dashboard
- Open Settings in the sidebar
- Select Advanced in the sidebar
- Scroll down to Skew Protection and enable the switch
- You can optionally set a custom maximum age (see limitations)
- Redeploy your latest production deployment.


By default, Skew Protection ignores the deployment ID on cross-origin requests. If another site fetches assets from your project with a ?dpl= parameter or x-deployment-id header, Skew Protection does not pin the request to the specified deployment. Instead, the request is routed to the latest production deployment.
This causes problems when your project serves assets that are fetched cross-origin by other domains. For example, if a client application embeds assets from your project at build time, the asset URLs are baked into the HTML with the deployment ID from that build. When your project later redeploys, those pinned asset URLs route to the new deployment where the old assets no longer exist, resulting in 404 errors and broken JavaScript and CSS.
This setting is not needed for Vercel Microfrontends because microfrontend projects share a domain, making all requests same-origin.
The Allowed Domains for Cross-Site Fetch setting solves this by specifying which external domains can make skew-protected requests to your project. Configure this on the project that serves the assets, not the project that consumes them.
- Select the project that serves the cross-site assets in the Vercel dashboard
- Open Settings in the sidebar
- Select Advanced in the sidebar
- Scroll down to Skew Protection and find Allowed Domains for Cross-Site Fetch
- Click Add Domain and enter a hostname (for example,
app.example.com) or a wildcard (for example,*.example.com) - Click Save
You can add up to 12 domains. Each entry accepts:
| Format | Example | What it matches |
|---|---|---|
| Bare hostname | example.com | Requests originating from example.com only |
| Hostname with subdomain | app.example.com | Requests originating from app.example.com only |
| Wildcard | *.example.com | Requests originating from any direct subdomain of example.com |
Wildcard entries only match one level of subdomain. For example, *.example.com matches app.example.com but not staging.app.example.com.
Inputs are normalized automatically: full URLs are reduced to their hostname, ports and paths are stripped, and values are lowercased.
When using cross-site Skew Protection, set the maximum age to a value greater than your typical deployment interval. If the serving project redeploys and the pinned deployment ages out of the maximum age window, cross-site requests will fail even with allowed domains configured.
The Maximum Age setting controls how long a deployment remains eligible for Skew Protection. If a client requests a deployment that no longer exists or is older than the configured maximum age (via the ?dpl= query parameter, x-deployment-id header, or __vdpl cookie), the request returns a 404.
To configure the maximum age:
- Select the project in the Vercel dashboard
- Open Settings in the sidebar
- Select Advanced in the sidebar
- Scroll down to Skew Protection and adjust the Maximum Age value
The default maximum age is one day from deployment creation. This strikes a good balance between protecting from version skew for frequently deployed projects and preventing old deployments from being accessed. However, if your users keep the website open for extended periods without refreshing, such as dashboards, monitoring tools, or long-running workflows, you may want to increase this value. You can configure a maximum age up to your project's Deployment Retention limit.
When you set a large maximum age, older deployments stay accessible for longer. If one of those deployments has a bug or security issue, you can either set a Custom Skew Protection Threshold or delete the deployment to stop clients from reaching it.
You can also use Deployment Retention to delete old deployments automatically. When your retention period is short, you can safely set the maximum age to the same value, since deployments are deleted before they could age out of the protection window. You only need a low maximum age if your deployment retention is long and you want to limit how far back Skew Protection reaches.
If a deployment has a bug or security issue, you can set a threshold to stop it and any deployments older than it from serving requests to active clients.
Once you deploy a fix, you can set a Skew Protection threshold with the following steps:
- Select the deployment that fixed the problem in the deployment list
- Select the button (near the Visit button)
- Click Skew Protection Threshold
- Click Set to apply the changes


You can observe how many requests are protected from version skew by visiting the Monitoring page in the Vercel dashboard.
For example, on the requests event, filter where skew_protection = 'active'.
You can view Edge Requests that are successfully fulfilled without the need for skew protection by using skew_protection = 'inactive'.


When using prebuilt deployments (via vercel deploy --prebuilt), you can configure a custom deployment ID to ensure Skew Protection works correctly. This is necessary when building your application outside of Vercel's build environment (via vercel build) to ensure the ID matches once deployed to Vercel.
For Next.js applications, configure the deploymentId in your next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
// Use a string value for the deployment ID
deploymentId: process.env.GIT_HASH || Date.now().toString(),
};
module.exports = nextConfig;User-configured deployment IDs have the following requirements:
- Cannot start with the
dpl_prefix - Must be unique per project
- Have a maximum length of 32 characters
- Can only contain alphanumeric characters (a-z, A-Z, 0-9), hyphens (-), and underscores (_)
If you attempt to use a deployment ID that already exists, the deployment will fail.
Skew Protection for prebuilt deployments with a custom deployment ID requires Next.js version greater than v16.2.0-canary.15 and Vercel CLI version greater than vercel@50.3.3. Custom deployment ID configuration is currently only available for Next.js and Build Output API. Other frameworks (SvelteKit, Qwik, Astro) do not support custom deployment IDs at this time.
For projects using the Build Output API, you can configure the deploymentId in your config.json file:
Generate your config.json file programmatically to include a unique deploymentId:
{
"version": 3,
"deploymentId": "<generated-at-build-time>"
}Skew Protection is available with zero configuration when Vercel runs your build. The following frameworks are supported:
Other frameworks can implement Skew Protection by checking if VERCEL_SKEW_PROTECTION_ENABLED has value 1
and then appending the value of VERCEL_DEPLOYMENT_ID to each request using one of the following options.
-
dplquery string parameter:option1.tsconst query = process.env.VERCEL_SKEW_PROTECTION_ENABLED === '1' ? `?dpl=${process.env.VERCEL_DEPLOYMENT_ID}` : ''; const res = await fetch(`/get${query}`); -
x-deployment-idheader:option2.tsconst headers = process.env.VERCEL_SKEW_PROTECTION_ENABLED === '1' ? { 'x-deployment-id': process.env.VERCEL_DEPLOYMENT_ID } : {}; const res = await fetch('/get', { headers }); -
__vdplcookie:option3.tsexport default function handler(req, res) { if ( process.env.VERCEL_SKEW_PROTECTION_ENABLED === '1' && req.headers['sec-fetch-dest'] === 'document' ) { res.setHeader('Set-Cookie', [ `__vdpl=${process.env.VERCEL_DEPLOYMENT_ID}; HttpOnly`, ]); } res.end('<h1>Hello World</h1>'); }
If you're building outside of Vercel using vercel build and then deploying with vercel deploy --prebuilt, Skew Protection requires a custom deployment ID so the
build-time ID matches the one Vercel assigns at deploy time.
See Custom Deployment ID for setup instructions.
For more information on prebuilt workflows, see When not to use --prebuilt.
If you are using Next.js 14.1.4 or newer and building on Vercel, there is no additional configuration needed to enable Skew Protection.
Older versions of Next.js require additional next.config.js configuration.
View config for 13.4.7 to 14.1.3
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
useDeploymentId: true,
// Optionally, use with Server Actions
useDeploymentIdServerActions: true,
},
};
module.exports = nextConfig;The useDeploymentId configuration enables Skew Protection for all framework-managed static file requests from your Next.js app such as for JavaScript and CSS files. You can also opt-into Skew Protection for Next.js Server Actions with useDeploymentIdServerActions.
If you are using SvelteKit, you will need to install @sveltejs/adapter-vercel version 5.2.0 or newer in order to enable Skew Protection.
Older versions can be upgraded by running npm i -D @sveltejs/adapter-vercel@latest.
If you are using Qwik 1.5.3 or newer, there is no additional configuration needed to enable Skew Protection.
Older versions can be upgraded by running npm i @builder.io/qwik@latest.
If you are using Astro, you will need to install @astrojs/vercel version 9.0.0 or newer in order to enable Skew Protection.
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
export default defineConfig({
// ...
output: 'server',
adapter: vercel({
skewProtection: true,
}),
});Older versions can be upgraded by running npm i -D @astrojs/vercel@latest.
If you are using Nuxt, there is no additional configuration needed to enable Skew Protection. Simply enable Skew Protection in the Vercel dashboard and Nuxt will automatically handle the deployment ID for framework-managed requests.
The default Skew Protection behavior works well for most applications. However, if your application has long-running client sessions where a full page reload would be disruptive, you can pin document navigations to a specific deployment using the __vdpl cookie.
When Vercel receives a request with the __vdpl cookie set, it routes that request to the deployment ID stored in the cookie, including document navigations. This prevents the hard refresh that would otherwise occur after a new deployment.
Common use cases include:
- Live assessments and exams: Test-taking platforms where a reload could cause lost progress or disqualification
- Real-time audio or video: Voice AI, telehealth, or streaming applications where a reload breaks the active connection
- Multi-step workflows: Long checkout flows, form wizards, or document editors with unsaved state
You can set the __vdpl cookie in Routing Middleware to pin all requests for the duration of a session:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const response = NextResponse.next();
const deploymentId = process.env.VERCEL_DEPLOYMENT_ID;
if (deploymentId && !request.cookies.get('__vdpl')) {
response.cookies.set('__vdpl', deploymentId, {
path: '/',
httpOnly: true,
sameSite: 'strict',
});
}
return response;
}With this middleware, the first request to your application sets the __vdpl cookie. All subsequent requests, including page navigations, route to the same deployment until you clear the cookie.
If you only need to pin certain parts of your application, add a matcher to the middleware so it only sets the cookie for matching paths:
// ... same middleware function as above
export const config = {
matcher: ['/exam/:path*', '/session/:path*'],
};When the user's session completes, clear the __vdpl cookie so subsequent visits load the latest deployment. You can do this from a Server Action:
'use server';
import { cookies } from 'next/headers';
export async function clearDeploymentPin() {
const cookieStore = await cookies();
cookieStore.delete('__vdpl');
}Then call the action from the client when the session ends:
'use client';
import { clearDeploymentPin } from '../actions';
export function SessionComplete() {
async function handleComplete() {
await clearDeploymentPin();
window.location.href = '/';
}
return <button onClick={handleComplete}>Finish session</button>;
}The __vdpl cookie pins requests to a specific deployment for as long as that
deployment remains accessible. If your retention
policy removes a deployment, Vercel can no longer
route to it, even with the cookie set.
Skew Protection is available for all deployment environments for Pro and Enterprise teams. You can configure a custom maximum age up to, but not exceeding, your project's retention policy.
Vercel automatically adjusts the maximum age to 60 days for requests from Googlebot and Bingbot in order to handle any delay between document crawl and render.
Deployments that have been deleted either manually or automatically using a retention policy will not be accessible through Skew Protection.
Was this helpful?