Skip to content
ExponaBLOG
SVELTE & SVELTEKIT · DAY 031 / 100

Adapters: deploying SvelteKit — best practices explained

Deploy SvelteKit anywhere with adapters for Node servers, Vercel, Cloudflare and static hosting — and pick the right one.

Expona Admin7 min read

Adapters: deploying SvelteKit — best practices explained

By day 31 of building with SvelteKit, you've likely crafted a solid application. Now comes the question: where do you actually run it? SvelteKit adapters are the bridge between your local development environment and production—they transform your code into a format your hosting platform understands. Without the right adapter, your application won't run anywhere.

Understanding adapters and platforms

An adapter in SvelteKit is a configuration that tells the framework how to build your application for a specific deployment target. Think of it as a translator: your SvelteKit code is universal, but each hosting platform speaks a different language. An adapter compiles your routes, handles server-side rendering, and prepares static assets in the format that platform expects.

The key decision is matching your adapter to your target platform. Here's the breakdown:

  • adapter-node: Generic Node.js server. Deploy on VPS, Docker, ECS, or any infrastructure that runs Node.
  • adapter-vercel: Optimized for Vercel. Serverless functions, edge middleware, and Vercel's deployment pipeline.
  • adapter-cloudflare: Cloudflare Pages or Workers. Edge runtime, no traditional servers.
  • adapter-static: Pure static output. Deploy on S3, Netlify, GitHub Pages, or any static host.

Each adapter compiles your application differently. adapter-node bundles everything into a Node process you control. adapter-vercel creates serverless functions for routes. adapter-cloudflare targets Cloudflare's V8 runtime. adapter-static pre-renders everything at build time.

adapter-node: Traditional server deployment

Use adapter-node when you need a traditional server you can run and manage. This is the most flexible option—it works everywhere Node.js runs.

First, install and configure it in svelte.config.js:

typescript
import adapter from '@sveltejs/adapter-node';

export default {
  kit: {
    adapter: adapter({
      out: 'build',
      precompress: true,
      envPrefix: 'PUBLIC_'
    })
  }
};

The precompress option automatically gzips assets, saving bandwidth. Build your app with npm run build, and it outputs a Node application in the build folder.

To run it in production, you typically use a process manager like PM2 or deploy via Docker:

typescript
// Dockerfile example
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY build ./build
COPY package.json ./
EXPOSE 3000
ENV NODE_ENV=production
CMD ["node", "build/index.js"]

The Node adapter is perfect for teams running their own infrastructure, using Kubernetes, or needing full control over the server environment. It's also the right choice when your application has compute-heavy operations that don't fit serverless constraints.

adapter-vercel: Serverless simplicity

If you're deploying to Vercel, the adapter-vercel package optimizes your build for their platform:

typescript
import adapter from '@sveltejs/adapter-vercel';

export default {
  kit: {
    adapter: adapter({
      runtime: 'nodejs18.x',
      memory: 1024,
      maxDuration: 60,
      regions: ['sfo1']
    })
  }
};

This configuration creates serverless functions for your routes, with each route potentially becoming its own function. Memory and duration limits apply—typical constraints for serverless—but scaling is automatic. Vercel handles SSL, CDN distribution, and deployment from Git seamlessly.

The real power emerges when you use Vercel's edge middleware or ISR (Incremental Static Regeneration). Many teams choose adapter-vercel specifically for its integrated deployment experience and zero-ops scaling.

adapter-cloudflare: Edge-first deployment

Cloudflare's adapter targets their edge runtime, executing your code across 300+ global data centers:

typescript
import adapter from '@sveltejs/adapter-cloudflare';

export default {
  kit: {
    adapter: adapter({
      routes: {
        include: ['/*'],
        exclude: ['']
      },
      platformProxy: {
        configPath: './wrangler.toml'
      }
    })
  }
};

Cloudflare's runtime is more constrained than Node.js—certain APIs don't exist—but latency is globally minimal. Your code runs on edge servers nearest to users. This is transformative for applications that need sub-50ms response times worldwide.

Pair this with a wrangler.toml configuration to bind KV storage, Durable Objects, or databases:

typescript
// wrangler.toml
name = "my-sveltekit-app"
type = "javascript"

[[env.production.kv_namespaces]]
binding = "CACHE"
id = "abc123..."

[[env.production.env.vars]]
PUBLIC_API_URL = "https://api.example.com"

Use Cloudflare when latency or global distribution is critical. Build a real-time app serving millions from a single codebase running on edge infrastructure.

adapter-static: Pre-render everything

When all your routes can be pre-rendered at build time, adapter-static outputs pure HTML, CSS, and JavaScript:

typescript
import adapter from '@sveltejs/adapter-static';

export default {
  kit: {
    adapter: adapter({
      pages: 'build',
      assets: 'build',
      fallback: '404.html',
      precompress: false
    }),
    prerender: {
      entries: ['/blog', '/docs', '/about'],
      crawl: true
    }
  }
};

Set prerender.crawl: true to automatically discover all pages by following links. Then deploy the output folder to S3, Netlify, GitHub Pages, or Cloudflare Pages with zero server cost.

Static hosting works beautifully for marketing sites, blogs, or documentation. If your app requires real-time data or user-specific content, you'll need API calls from the browser or a hybrid approach combining static pre-rendering with edge functions.

adapter-auto: Let SvelteKit decide

During development or when you're uncertain about your deployment target, use adapter-auto:

typescript
import adapter from '@sveltejs/adapter-auto';

export default {
  kit: {
    adapter: adapter()
  }
};

This adapter detects common environments at build time. Deploying to Vercel? It uses adapter-vercel. Cloudflare? adapter-cloudflare. GitHub Pages? adapter-static. Running on a VPS with Node? adapter-node.

adapter-auto is convenient during prototyping but we recommend explicitly choosing your adapter once your deployment strategy is clear. Explicit configuration makes your build behavior predictable and easier to debug in CI/CD pipelines.

Environment variables across platforms

Each platform manages environment variables differently, but SvelteKit's convention is consistent. Use the PUBLIC_ prefix for variables exposed to the browser:

typescript
// src/lib/config.ts
export const API_URL = import.meta.env.PUBLIC_API_URL;
export const API_SECRET = import.meta.env.API_SECRET; // Server-only, never exposed

In your adapter configuration, set envPrefix if you want a custom prefix:

typescript
export default {
  kit: {
    adapter: adapter({
      envPrefix: 'MYAPP_'
    })
  }
};

Then on your platform:

  • Vercel: Set in project settings or .env.local
  • Cloudflare: Define in wrangler.toml under [env.vars]
  • Node/Docker: Pass via docker run -e PUBLIC_API_URL=...` or your orchestration tool
  • Static hosts: Build-time only; pass to the build command

Edge runtimes: Vercel and Cloudflare

Both Vercel and Cloudflare support edge runtimes—code that runs closer to users with lower latency. SvelteKit hooks into this via server hooks.

Create an +server.ts route to run on edge:

typescript
// src/routes/api/fast/+server.ts
import { json } from '@sveltejs/kit';
import type { RequestHandler } from '@sveltejs/kit';

export const GET: RequestHandler = async ({ platform }) => {
  // On Vercel, this can run at the edge
  // On Cloudflare, this runs on the edge by default
  
  const data = {
    timestamp: new Date().toISOString(),
    region: platform?.cf?.colo || 'unknown'
  };
  
  return json(data, {
    headers: {
      'Cache-Control': 'public, max-age=60'
    }
  });
};

For Vercel, declare edge functions in your config:

typescript
import adapter from '@sveltejs/adapter-vercel';

export default {
  kit: {
    adapter: adapter(),
    paths: {
      base: '/api'
    }
  }
};

Edge runtimes matter when you need global low-latency response—think real-time dashboards, geolocated content, or rate limiting. For most applications, the performance difference is marginal; use them strategically.

Common mistakes

Switching adapters without rebuilding: Each adapter produces different output. Never copy a build from one adapter to another platform. Always run npm run build after changing your adapter configuration.

Forgetting environment-specific configuration: An adapter works on your laptop but fails in production because environment variables aren't set. Always define all required env vars on your platform before deploying.

Using Node-specific APIs with edge adapters: Code like fs.readFileSync or require breaks on edge runtimes. Use platform context to access platform-specific APIs instead.

Over-prerendering static sites: Setting prerender: true on every route bloats build time and size. Only pre-render content that's stable—use dynamic routes with API calls for user-specific data.

Ignoring build output size: Serverless platforms charge by execution time and memory. Monitor your build size and dependencies. Unused code increases cold start latency.

Key takeaways

  • Choose your adapter based on your hosting platform: adapter-node for traditional servers, adapter-vercel for Vercel, adapter-cloudflare for edge, adapter-static for static hosts.
  • Use adapter-auto during development, but always explicitly configure your adapter in production.
  • Environment variables follow a consistent SvelteKit convention with the PUBLIC_ prefix, but deployment methods vary per platform.
  • Edge runtimes (Vercel, Cloudflare) offer global low-latency response, but come with API constraints—test your code on the actual platform.
  • Rebuild your application whenever you change adapters; never reuse builds across platforms.
  • Monitor build size and cold start performance, especially for serverless deployments.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles