Deploy SvelteKit to Vercel: The Complete Guide
Deploy SvelteKit to Vercel: The Complete Guide
Deploying a SvelteKit application to Vercel is one of the smoothest deployment experiences available. Vercel's first-class support for SvelteKit means you get automatic builds, preview deployments for every pull request, edge functions, and a global CDN — all with minimal configuration.
This guide covers everything from initial setup to advanced optimization techniques. Whether you are deploying your first SvelteKit app or migrating an existing one, you will find everything you need here.
Prerequisites
Before you begin, make sure you have:
- A SvelteKit project ready to deploy
- A Vercel account (free tier is generous)
- Git repository hosted on GitHub, GitLab, or Bitbucket
- Node.js 18+ installed locally
Step 1: Install the Vercel Adapter
SvelteKit uses adapters to target different deployment platforms. The Vercel adapter transforms your SvelteKit app into a format optimized for Vercel's infrastructure.
npm install -D @sveltejs/adapter-vercel
Update your svelte.config.js to use the Vercel adapter:
import adapter from '@sveltejs/adapter-vercel';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter({
// Deployment configuration options
runtime: 'nodejs22.x',
regions: ['iad1'], // US East by default
split: false
})
}
};
export default config;
The runtime option specifies the Node.js version. The regions option controls where your serverless functions deploy. The split option determines whether each route gets its own serverless function (useful for large apps to avoid cold start times).
Step 2: Configure Environment Variables
Environment variables in SvelteKit follow a specific naming convention. Variables prefixed with PUBLIC_ are exposed to the browser, while others remain server-side only.
In your Vercel project dashboard, go to Settings > Environment Variables and add your variables:
# Server-only variables (never sent to the browser)
DATABASE_URL=postgresql://...
SUPABASE_SERVICE_ROLE_KEY=eyJ...
API_SECRET=your-secret-key
# Public variables (available in browser code)
PUBLIC_SUPABASE_URL=https://your-project.supabase.co
PUBLIC_SUPABASE_ANON_KEY=eyJ...
PUBLIC_APP_URL=https://your-app.vercel.app
You can set different values for Production, Preview, and Development environments. This is particularly useful for staging databases or test API keys.
In your SvelteKit code, access these variables properly:
// Server-side only (in +page.server.ts, +server.ts, hooks.server.ts)
import { DATABASE_URL, API_SECRET } from '$env/static/private';
// Available everywhere (including browser)
import { PUBLIC_SUPABASE_URL } from '$env/static/public';
// Dynamic environment variables (resolved at runtime)
import { env } from '$env/dynamic/private';
const dbUrl = env.DATABASE_URL;
Step 3: Deploy via Git Integration
The simplest way to deploy is connecting your Git repository to Vercel:
- Go to vercel.com/new
- Import your Git repository
- Vercel automatically detects SvelteKit and configures the build settings
- Click Deploy
Vercel will automatically:
- Install dependencies
- Run
npm run build(or your custom build command) - Deploy the output to their global CDN
- Set up preview deployments for future pull requests
For manual deployments or CI/CD pipelines, you can also use the Vercel CLI:
npm install -g vercel
# Deploy to preview
vercel
# Deploy to production
vercel --prod
Step 4: Enable Edge Functions
Edge functions run closer to your users, reducing latency significantly. SvelteKit makes it easy to run specific routes at the edge:
// src/routes/api/fast-endpoint/+server.ts
export const config = {
runtime: 'edge'
};
export async function GET() {
return new Response(JSON.stringify({
message: 'This runs at the edge!',
timestamp: Date.now()
}), {
headers: { 'Content-Type': 'application/json' }
});
}
You can also configure edge runtime for pages:
// src/routes/dashboard/+page.server.ts
export const config = {
runtime: 'edge',
regions: ['iad1', 'sfo1', 'cdg1'] // Multi-region
};
export async function load() {
// This load function runs at the edge
return {
timestamp: new Date().toISOString()
};
}
When to use edge functions:
- API routes that do not need Node.js-specific APIs
- Pages with dynamic data that benefit from low latency
- Middleware-like operations (redirects, authentication checks)
When to avoid edge functions:
- Routes that use Node.js built-in modules (fs, crypto with certain APIs)
- Heavy computational tasks
- Routes that need to connect to databases not available at the edge
Step 5: Implement Incremental Static Regeneration (ISR)
ISR lets you serve static pages that automatically revalidate after a specified time. This gives you the performance of static sites with the freshness of server-rendered pages:
// src/routes/blog/[slug]/+page.server.ts
export const config = {
isr: {
expiration: 60, // Revalidate every 60 seconds
allowQuery: ['ref'] // Cache varies by these query params
}
};
export async function load({ params }) {
const post = await fetchBlogPost(params.slug);
return { post };
}
For pages that rarely change, use longer expiration times:
export const config = {
isr: {
expiration: 3600 // Revalidate every hour
}
};
You can also set expiration: false for pages that should be statically generated once and never revalidated until the next deployment.
Step 6: Configure Preview Deployments
Every pull request automatically gets a preview deployment with its own URL. This is incredibly useful for code review and testing.
Customize preview behavior in vercel.json:
{
"git": {
"deploymentEnabled": {
"main": true,
"staging": true
}
},
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-Content-Type-Options",
"value": "nosniff"
}
]
}
],
"redirects": [
{
"source": "/old-path",
"destination": "/new-path",
"permanent": true
}
]
}
Step 7: Set Up a Custom Domain
Adding a custom domain to your Vercel deployment:
- Go to your project Settings > Domains
- Add your domain (e.g.,
myapp.com) - Configure DNS records as instructed by Vercel
- Vercel automatically provisions an SSL certificate
For apex domains (e.g., myapp.com without www), you need to add an A record pointing to Vercel's IP address. For subdomains, use a CNAME record.
Update your SvelteKit app to use the custom domain:
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
// Redirect www to non-www
if (event.url.hostname.startsWith('www.')) {
const newUrl = new URL(event.url);
newUrl.hostname = newUrl.hostname.slice(4);
return new Response(null, {
status: 301,
headers: { Location: newUrl.toString() }
});
}
return resolve(event);
};
Step 8: Optimize for Production
Several optimizations can improve your production deployment:
Enable compression and caching:
// src/hooks.server.ts
export const handle: Handle = async ({ event, resolve }) => {
const response = await resolve(event);
// Add caching headers for static assets
if (event.url.pathname.startsWith('/_app/')) {
response.headers.set(
'Cache-Control',
'public, max-age=31536000, immutable'
);
}
return response;
};
Prerender static pages:
// src/routes/about/+page.ts
export const prerender = true;
Use streaming for slow data:
// src/routes/dashboard/+page.server.ts
export async function load() {
return {
// Fast data loads immediately
user: await getUser(),
// Slow data streams in
analytics: getAnalytics() // Note: no await
};
}
<!-- src/routes/dashboard/+page.svelte -->
<script lang="ts">
let { data } = $props();
</script>
<h1>Welcome, {data.user.name}</h1>
{#await data.analytics}
<p>Loading analytics...</p>
{:then analytics}
<AnalyticsDashboard {analytics} />
{/await}
Troubleshooting Common Issues
Build fails with "Cannot find module" errors:
Make sure all dependencies are in dependencies, not just devDependencies, if they are needed at runtime. Server-side code runs in a serverless function that only has access to production dependencies.
Environment variables are undefined:
Double-check that you have added them in the Vercel dashboard. Remember that $env/static/private variables are inlined at build time, so you need to redeploy after changing them. Use $env/dynamic/private if you need runtime resolution.
API routes return 404:
Verify your route files follow the correct naming convention: +server.ts for API endpoints, +page.server.ts for page data loading.
Cold starts are slow:
Consider using edge functions for latency-sensitive routes. You can also use the split: true option in the adapter to create smaller, faster-loading function bundles.
CORS issues: Handle CORS in your API routes:
// src/routes/api/data/+server.ts
export async function OPTIONS() {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
}
});
}
Monitoring and Analytics
Vercel provides built-in analytics and monitoring:
- Web Analytics: Track page views and visitor data
- Speed Insights: Monitor Core Web Vitals
- Logs: View serverless function logs in real-time
- Usage: Monitor bandwidth and function invocations
Enable Web Analytics in your SvelteKit app:
npm install @vercel/analytics
<!-- src/routes/+layout.svelte -->
<script>
import { dev } from '$app/environment';
import { inject } from '@vercel/analytics';
inject({ mode: dev ? 'development' : 'production' });
</script>
<slot />
Summary
Deploying SvelteKit to Vercel gives you a production-ready setup with:
- Zero-configuration builds with automatic framework detection
- Preview deployments for every pull request
- Edge functions for low-latency endpoints
- ISR for pages that need periodic revalidation
- Global CDN with automatic SSL
- Built-in analytics and monitoring
The SvelteKit-Vercel combination is particularly powerful because both tools share a philosophy of doing the right thing by default while allowing deep customization when you need it. Start with the defaults, measure your performance, and optimize only where the data tells you to.
Source: Teta Engineering
This content was generated with AI from public sources. It represents analysis and commentary, not original journalism.