teta.so
SvelteKitVercelDeploymentTutorial

Deploy SvelteKit to Vercel: The Complete Guide

AI Generated

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:

  1. Go to vercel.com/new
  2. Import your Git repository
  3. Vercel automatically detects SvelteKit and configures the build settings
  4. 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:

  1. Go to your project Settings > Domains
  2. Add your domain (e.g., myapp.com)
  3. Configure DNS records as instructed by Vercel
  4. 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.

Build your next app with AI

Try Teta — create sites and apps with AI agents.

Get started free