
Research
/Security News
Mini Shai-Hulud Campaign Hits Red Hat Cloud Services npm Packages
A mini Shai-Hulud campaign compromised Red Hat Cloud Services npm packages to steal developer and CI/CD secrets during installation.
@vercel/config
Advanced tools
TypeScript SDK for defining Vercel configuration programmatically.
npm install @vercel/config
Create a vercel.ts file in your project root:
import { createRouter } from '@vercel/config';
const router = createRouter();
// Basic rewrite
router.rewrite('/api/(.*)', 'https://backend.com/$1');
// Rewrite with transforms
router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({
requestHeaders: {
'x-user-id': userId,
'authorization': `Bearer ${env.API_TOKEN}`
}
}));
// Redirects
router.redirect('/old-docs', '/docs', { permanent: true });
// Cache control
router.cacheControl('/static/(.*)', {
public: true,
maxAge: '1 week',
immutable: true
});
// Global settings
router.cleanUrls = true;
router.trailingSlash = true;
// Bulk redirects
router.bulkRedirectsPath = './bulkRedirectsDemo.json';
// Cron jobs
router.cron('/api/cleanup', '0 0 * * *');
export default router.getConfig();
Your vercel.ts file is automatically compiled when you run:
vercel build # For local builds
vercel dev # For local development
vercel deploy # For deployment
The Vercel CLI automatically compiles vercel.ts to .vercel/vercel.json before building or deploying.
createRouter()Creates a new router instance.
router.rewrite(source, destination, options?)Add a rewrite rule. Options can be an object or a callback function that receives path parameters and environment variables.
// With callback for transforms
router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({
requestHeaders: {
'x-user-id': userId,
'authorization': `Bearer ${env.API_TOKEN}`
},
responseHeaders: {
'x-powered-by': 'My API'
},
requestQuery: {
'version': '2.0'
}
}));
// Simple rewrite without transforms
router.rewrite('/api/(.*)', 'https://backend.com/$1');
router.redirect(source, destination, options?)Add a redirect rule. Options include permanent and statusCode.
router.redirect('/old-page', '/new-page', { permanent: true });
router.redirect('/temp', '/elsewhere', { statusCode: 302 });
router.header(source, headers, options?)Add custom headers for a path pattern.
router.header('/api/(.*)', [
{ key: 'X-Custom-Header', value: 'value' }
]);
router.cacheControl(source, options)Set cache control headers. Options include public, private, maxAge, sMaxAge, immutable, etc.
router.cacheControl('/static/(.*)', {
public: true,
maxAge: '1 week',
immutable: true
});
router.cleanUrlsSet whether to enable clean URLs (removes file extensions).
router.cleanUrls = true;
router.trailingSlashSet whether to normalize paths to include trailing slashes.
router.trailingSlash = true;
router.bulkRedirectsPathSet the path to a bulk redirects JSON file.
router.bulkRedirectsPath = './bulkRedirectsDemo.json';
The SDK supports powerful conditional routing using has and missing conditions. These conditions can be added to rewrites, redirects, headers, and cache control rules.
header: Match HTTP headerscookie: Match cookieshost: Match the request hostquery: Match query parameterspath: Match the request path pattern// Only rewrite if x-api-key header exists
router.rewrite('/api/(.*)', 'https://backend.com/$1', {
has: [
{ type: 'header', key: 'x-api-key' }
]
});
// Redirect if auth-token cookie is missing
router.redirect('/dashboard', '/login', {
missing: [
{ type: 'cookie', key: 'auth-token' }
]
});
The SDK supports advanced matching operators for more complex conditions:
// Exact match using 'eq'
router.rewrite('/api/(.*)', 'https://backend.com/$1', {
has: [
{ type: 'header', key: 'x-api-version', eq: 'v2' }
]
});
// Not equal using 'neq'
router.redirect('/beta/(.*)', '/stable/$1', {
has: [
{ type: 'cookie', key: 'beta-access', neq: 'granted' }
]
});
// Must be one of (inclusion)
router.rewrite('/admin/(.*)', 'https://admin.backend.com/$1', {
has: [
{ type: 'header', key: 'x-user-role', inc: ['admin', 'moderator', 'superuser'] }
]
});
// Must NOT be one of (non-inclusion)
router.redirect('/public/(.*)', '/private/$1', {
has: [
{ type: 'header', key: 'x-user-role', ninc: ['guest', 'anonymous'] }
]
});
// Starts with (prefix)
router.rewrite('/staging/(.*)', 'https://staging.backend.com/$1', {
has: [
{ type: 'cookie', key: 'session', pre: 'staging-' }
]
});
// Ends with (suffix)
router.redirect('/dev/(.*)', '/development/$1', {
has: [
{ type: 'header', key: 'x-environment', suf: '-dev' }
]
});
// Greater than
router.rewrite('/api/v3/(.*)', 'https://api-v3.backend.com/$1', {
has: [
{ type: 'query', key: 'version', gt: 2 }
]
});
// Greater than or equal
router.rewrite('/premium/(.*)', '/premium-content/$1', {
has: [
{ type: 'header', key: 'x-subscription-tier', gte: 3 }
]
});
// Less than
router.redirect('/legacy/(.*)', '/upgrade/$1', {
has: [
{ type: 'query', key: 'api-version', lt: 2 }
]
});
// Less than or equal
router.rewrite('/free/(.*)', '/free-tier/$1', {
has: [
{ type: 'header', key: 'x-plan', lte: 1 }
]
});
// Host matching (no key required)
router.redirect('/(.*)', 'https://www.example.com/$1', {
has: [
{ type: 'host', value: 'example.com' }
]
});
// Path pattern matching (no key required)
router.rewrite('/(.*)', '/internal/$1', {
has: [
{ type: 'path', value: '^/api/v[0-9]+/.*' }
]
});
All conditions in a has or missing array must match (AND logic):
router.rewrite('/secure/(.*)', 'https://secure.backend.com/$1', {
has: [
{ type: 'header', key: 'x-api-key' },
{ type: 'header', key: 'x-user-role', inc: ['admin', 'superuser'] },
{ type: 'cookie', key: 'session', pre: 'secure-' },
{ type: 'query', key: 'version', gte: 2 }
]
});
You can combine conditions with transforms for powerful routing logic:
router.rewrite('/api/users/:userId', 'https://backend.com/users/$1', ({ userId, env }) => ({
has: [
{ type: 'header', key: 'authorization', pre: 'Bearer ' },
{ type: 'header', key: 'x-api-version', gte: 2 }
],
missing: [
{ type: 'header', key: 'x-deprecated-header' }
],
requestHeaders: {
'x-user-id': userId,
'x-internal-key': env.INTERNAL_API_KEY
}
}));
| Operator | Type | Description | Example |
|---|---|---|---|
eq | string | number | Exact equality match | { eq: 'v2' } |
neq | string | Not equal | { neq: 'guest' } |
inc | string[] | Value is one of | { inc: ['admin', 'mod'] } |
ninc | string[] | Value is not one of | { ninc: ['guest', 'banned'] } |
pre | string | Starts with prefix | { pre: 'Bearer ' } |
suf | string | Ends with suffix | { suf: '-dev' } |
gt | number | Greater than | { gt: 2 } |
gte | number | Greater than or equal | { gte: 3 } |
lt | number | Less than | { lt: 5 } |
lte | number | Less than or equal | { lte: 10 } |
vercel.ts and vercel.json. The build will fail if both exist..vercel/vercel.json file is automatically ignored by git (in the .vercel/ directory).FAQs
A TypeScript SDK for programmatically configuring Vercel projects
The npm package @vercel/config receives a total of 181,291 weekly downloads. As such, @vercel/config popularity was classified as popular.
We found that @vercel/config demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
A mini Shai-Hulud campaign compromised Red Hat Cloud Services npm packages to steal developer and CI/CD secrets during installation.

Research
/Security News
The North Korean malware loader hides in a Packagist-listed package and its GitHub branch to fetch and execute remote code in a likely Contagious Interview-style lure.

Security News
The Rust project is moving toward formal rules on LLM use in contributions after months of internal debate over maintainer burden, code quality, and contributor experience.