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:
- Renaming
"scripts"
to"tasks"
- Prefixing npm packages with
npm:
- 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
.

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.