· 8 Min read

SvelteKit Deno Setup Guide: From CLI to Production

SvelteKit Deno Setup Guide: From CLI to Production

SvelteKit's partnership with Deno has reached a new level of maturity. With the recent updates to the sv CLI and native Deno support in SvelteKit 2.31.0, you can now build full-stack applications using Deno's modern runtime from day one.

This guide walks you through setting up a production-ready SvelteKit application with Deno, covering everything from initial project creation to deployment. You'll learn to navigate the differences between Node.js and Deno workflows, handle common configuration issues, and leverage Deno's built-in tooling.

Link to section: Prerequisites and Environment SetupPrerequisites and Environment Setup

Before starting, install Deno 1.45.0 or later. The installation process varies by operating system:

# macOS/Linux
curl -fsSL https://deno.land/install.sh | sh
 
# Windows (PowerShell)
irm https://deno.land/install.ps1 | iex
 
# Verify installation
deno --version

You'll also need the latest sv CLI tool, which now includes first-class Deno support:

npm install -g sv@latest
# or
npx sv@latest --version

The sv CLI version 0.9.0 introduced the --no-git-check flag and improved Deno integration. If you're using an older version, update it before proceeding.

Link to section: Creating Your SvelteKit Project with DenoCreating Your SvelteKit Project with Deno

The sv create command now offers Deno as a package manager option during project setup. Run the following command to start the interactive setup:

npx sv create my-deno-app

When prompted, make these selections:

  • Template: SvelteKit minimal (for this tutorial)
  • Type checking: TypeScript
  • Package manager: Deno
  • Additional tools: Tailwind CSS (optional but recommended)

The CLI creates a project structure with a deno.json file instead of package.json. This file contains Deno-specific configuration:

{
  "tasks": {
    "dev": "deno run -A npm:vite dev",
    "build": "deno run -A npm:vite build",
    "preview": "deno run -A npm:vite preview"
  },
  "nodeModulesDir": "auto",
  "fmt": {
    "unstable": ["fmt-component"]
  },
  "lint": {
    "include": ["src/**/*.{ts,js,svelte}"],
    "exclude": ["node_modules", ".svelte-kit", "dist", "build"],
    "rules": {
      "tags": ["recommended"]
    }
  }
}

Link to section: Converting Node.js Configuration to DenoConverting Node.js Configuration to Deno

If you're migrating an existing SvelteKit project or need to manually configure Deno support, you'll need to convert your package.json scripts to Deno tasks. The key changes involve:

  1. Renaming "scripts" to "tasks"
  2. Prefixing npm packages with npm:
  3. Adding the -A flag for permissions

Here's the conversion pattern:

// Before (package.json)
{
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "test": "vitest"
  }
}
 
// After (deno.json)
{
  "tasks": {
    "dev": "deno run -A npm:vite dev",
    "build": "deno run -A npm:vite build",
    "test": "deno run -A npm:vitest"
  }
}

The -A flag grants all permissions. For production environments, you might want to use more specific permissions:

{
  "tasks": {
    "dev": "deno run --allow-net --allow-read --allow-write --allow-env npm:vite dev"
  }
}

Link to section: Essential Deno ConfigurationEssential Deno Configuration

Add these essential configuration blocks to your deno.json:

{
  "nodeModulesDir": "auto",
  "fmt": {
    "unstable": ["fmt-component"]
  },
  "lint": {
    "include": ["src/**/*.{ts,js,svelte}"],
    "exclude": ["node_modules", ".svelte-kit", ".vite", "dist", "build"],
    "rules": {
      "tags": ["recommended"]
    }
  }
}

The nodeModulesDir: "auto" setting ensures Deno creates a node_modules directory for npm packages, which SvelteKit's bundler expects. The fmt-component unstable feature enables Svelte component formatting with deno fmt.

Screenshot showing SvelteKit project structure with Deno configuration files

Link to section: Setting Up Development TasksSetting Up Development Tasks

Expand your deno.json tasks to include common development workflows:

{
  "tasks": {
    "dev": "deno run -A npm:vite dev",
    "build": "deno run -A npm:vite build",
    "preview": "deno run -A npm:vite preview",
    "check": "deno run -A npm:svelte-check --tsconfig ./tsconfig.json",
    "format": "deno fmt",
    "format:check": "deno fmt --check",
    "lint": "deno lint",
    "lint:fix": "deno lint --fix",
    "test": "deno run -A npm:vitest",
    "test:ui": "deno run -A npm:vitest --ui"
  }
}

Start your development server:

deno task dev

You should see output similar to:

  VITE v5.4.0  ready in 324 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

Link to section: Working with Async ComponentsWorking with Async Components

SvelteKit's async component support pairs well with Deno's modern async capabilities. Enable async components in your svelte.config.js:

import adapter from '@sveltejs/adapter-auto';
 
/** @type {import('@sveltejs/kit').Config} */
const config = {
  kit: {
    adapter: adapter()
  },
  compilerOptions: {
    experimental: {
      async: true
    }
  }
};
 
export default config;

Now you can use await directly in your components:

<!-- src/routes/+page.svelte -->
<script>
  const data = await fetch('https://jsonplaceholder.typicode.com/posts/1')
    .then(r => r.json());
</script>
 
<h1>{data.title}</h1>
<p>{data.body}</p>

This eliminates the need for onMount hooks in many data-fetching scenarios. The Svelte compiler generates optimized code that handles loading states automatically.

Link to section: Handling Deno-Specific ImportsHandling Deno-Specific Imports

Deno supports both npm packages and URL imports. For SvelteKit projects, stick with npm imports in your Svelte components to maintain compatibility with the bundler:

// Good - works with SvelteKit bundler
import { writable } from 'svelte/store';
import lodash from 'npm:lodash';
 
// Bad - URL imports don't work with Vite
import lodash from 'https://esm.sh/lodash';

For server-side code in +page.server.js or +layout.server.js, you can use Deno's URL imports:

// src/routes/api/+server.js
import { json } from '@sveltejs/kit';
 
export async function GET() {
  const { format } = await import('https://deno.land/std@0.200.0/datetime/mod.ts');
  
  return json({
    timestamp: format(new Date(), 'yyyy-MM-dd HH:mm:ss')
  });
}

Link to section: Troubleshooting Common IssuesTroubleshooting Common Issues

Permission Errors

If you encounter permission errors, check your task definitions include appropriate flags:

# Error: Requires net access to "127.0.0.1:5173"
# Fix: Add --allow-net or use -A
"dev": "deno run --allow-net --allow-read npm:vite dev"

Module Resolution Problems

When npm packages fail to resolve, ensure nodeModulesDir is set correctly:

{
  "nodeModulesDir": "auto"
}

Delete any existing node_modules directory and restart the dev server to regenerate it.

TypeScript Configuration Conflicts

Deno and Node.js have different TypeScript defaults. Create a tsconfig.json that works with both:

{
  "extends": "./.svelte-kit/tsconfig.json",
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "strict": true,
    "moduleResolution": "bundler"
  }
}

Link to section: Testing with Deno and VitestTesting with Deno and Vitest

Configure Vitest to work with Deno by updating your vite.config.js:

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
 
export default defineConfig({
  plugins: [sveltekit()],
  test: {
    include: ['src/**/*.{test,spec}.{js,ts}'],
    environment: 'jsdom'
  }
});

Install the necessary testing dependencies:

deno add npm:@testing-library/svelte npm:@testing-library/jest-dom npm:jsdom

Create a simple test to verify your setup:

// src/lib/utils.test.js
import { expect, test } from 'vitest';
 
export function add(a, b) {
  return a + b;
}
 
test('adds 1 + 2 to equal 3', () => {
  expect(add(1, 2)).toBe(3);
});

Run tests with:

deno task test

Link to section: Building and Deployment PreparationBuilding and Deployment Preparation

Build your application for production:

deno task build

The build process creates a .svelte-kit/output directory containing your compiled application. For Deno deployment, you'll typically use the Node.js adapter since most hosting platforms that support Deno also support Node.js applications.

If you're deploying to Deno Deploy, create a simple server file:

// server.js
import { serve } from 'https://deno.land/std@0.200.0/http/server.ts';
import { handler } from './.svelte-kit/output/server/index.js';
 
serve(handler, { port: 8000 });

Link to section: Advanced Configuration and Production ConsiderationsAdvanced Configuration and Production Considerations

For production deployments, consider these additional configurations:

Environment Variables

Deno handles environment variables differently than Node.js. Create a .env file and load it explicitly:

// src/hooks.server.js
import { dev } from '$app/environment';
 
if (dev) {
  await import('https://deno.land/std@0.200.0/dotenv/load.ts');
}

Performance Optimization

Enable Deno's V8 compile cache for faster startup times:

{
  "tasks": {
    "dev": "deno run -A --v8-flags=--max-old-space-size=4096 npm:vite dev"
  }
}

Security Hardening

For production, use minimal permissions instead of -A:

{
  "tasks": {
    "start": "deno run --allow-net=:8000 --allow-read=. --allow-env server.js"
  }
}

Link to section: Editor Integration and Developer ExperienceEditor Integration and Developer Experience

Configure VS Code for optimal Deno development by creating .vscode/settings.json:

{
  "deno.enable": true,
  "deno.enablePaths": ["./deno.json"],
  "editor.defaultFormatter": "denoland.vscode-deno",
  "editor.formatOnSave": true,
  "[typescript]": {
    "editor.defaultFormatter": "denoland.vscode-deno"
  },
  "[javascript]": {
    "editor.defaultFormatter": "denoland.vscode-deno"
  }
}

Install the official Deno extension for VS Code to get full IntelliSense, formatting, and linting support.

Link to section: Real-world Example: API IntegrationReal-world Example: API Integration

Here's a practical example combining SvelteKit's server-side capabilities with Deno's built-in features:

// src/routes/api/weather/+server.js
import { json, error } from '@sveltejs/kit';
 
export async function GET({ url }) {
  const city = url.searchParams.get('city');
  
  if (!city) {
    throw error(400, 'City parameter required');
  }
 
  try {
    const response = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${Deno.env.get('WEATHER_API_KEY')}`
    );
    
    if (!response.ok) {
      throw error(response.status, 'Weather API error');
    }
    
    const data = await response.json();
    return json(data);
  } catch (err) {
    throw error(500, 'Failed to fetch weather data');
  }
}

This server endpoint demonstrates proper error handling, environment variable access, and JSON response formatting in a Deno environment.

Link to section: Next Steps and Advanced FeaturesNext Steps and Advanced Features

With your basic SvelteKit + Deno setup complete, consider exploring these advanced features:

Remote Functions Integration: SvelteKit's RPC-style server functions work seamlessly with Deno's runtime capabilities.

WebSocket Support: Deno's built-in WebSocket support pairs well with SvelteKit's real-time features for building interactive applications.

Edge Computing: Deploy your SvelteKit app to Deno Deploy for global edge distribution with zero-config deployments.

The combination of SvelteKit and Deno provides a modern, efficient development experience that eliminates many traditional Node.js pain points while maintaining full compatibility with the npm ecosystem. This setup gives you the best of both worlds: Deno's security model and built-in tooling, plus SvelteKit's excellent developer experience and performance characteristics.