Deploying a SvelteKit App
SvelteKit is a modern meta-framework for Svelte that enables building fast, reactive web applications with excellent performance characteristics. It features file-based routing, server-side rendering (SSR), static site generation (SSG), API routes for backend functionality, form actions for handling submissions, hooks for request processing, and image optimization. SvelteKit compiles Svelte components to highly efficient vanilla JavaScript with minimal bundle sizes, making it ideal for building performant, user-friendly web applications that work offline and load quickly on any device.
This comprehensive guide walks you through deploying a SvelteKit application to Klutch.sh, covering both automatic Nixpacks-based deployments and Docker-based deployments. You’ll learn installation steps, explore sample code, configure adapters, set up environment variables, build API routes, and discover best practices for production deployments.
Table of Contents
- Prerequisites
- Getting Started: Create a SvelteKit App
- Sample Code Examples
- Project Structure
- SvelteKit Adapters & Configuration
- Deploying Without a Dockerfile (Nixpacks)
- Deploying With a Dockerfile
- Environment Variables & Configuration
- Server Routes & API Endpoints
- Form Actions & Progressive Enhancement
- Troubleshooting
- Resources
Prerequisites
To deploy a SvelteKit application on Klutch.sh, ensure you have:
- Node.js 18 or higher - SvelteKit requires a modern Node.js version
- npm or yarn - For managing dependencies
- Git - For version control
- GitHub account - Klutch.sh integrates with GitHub for continuous deployments
- Klutch.sh account - Sign up for free
Getting Started: Create a SvelteKit App
Follow these steps to create and set up a new SvelteKit application:
-
Create a new SvelteKit app using the official create-svelte command:
Terminal window npm create svelte@latest my-sveltekit-appcd my-sveltekit-appnpm installThe CLI will ask about TypeScript, testing libraries, and other options. Select your preferences.
-
Start the development server:
Terminal window npm run devYour SvelteKit app will be available at http://localhost:5173. The development server includes hot module reloading for instant feedback.
- Explore the generated project structure. SvelteKit creates a `routes` directory under `src` where you can add pages and API endpoints. The framework automatically generates routes based on your file structure.
-
Build your application for production:
Terminal window npm run buildnpm run previewThis creates an optimized build and allows you to preview the production build locally.
- Stop the development server when ready, press `Ctrl+C`. Verify your app builds successfully before deploying to Klutch.sh.
Sample Code Examples
Basic Page with Svelte Components
Here’s an example of a SvelteKit page with reactive state:
<script> let count = 0; let name = '';
function increment() { count += 1; }
function handleNameChange(event) { name = event.target.value; }</script>
<svelte:head> <title>Home - SvelteKit on Klutch.sh</title> <meta name="description" content="Welcome to SvelteKit" /></svelte:head>
<div class="container"> <h1>Welcome to SvelteKit</h1> <p>Deployed on Klutch.sh</p>
<section> <h2>Counter: {count}</h2> <button on:click={increment}>Increment</button> </section>
<section> <label> Your name: <input type="text" value={name} on:change={handleNameChange} /> </label> {#if name} <p>Hello, {name}!</p> {/if} </section></div>
<style> .container { max-width: 800px; margin: 0 auto; padding: 2rem; }
button { padding: 0.5rem 1rem; font-size: 1rem; cursor: pointer; }</style>API Route (Server Function)
import type { RequestHandler } from '@sveltejs/kit';
export const GET: RequestHandler = async () => { const posts = [ { id: 1, title: 'First Post', content: 'Hello world' }, { id: 2, title: 'Second Post', content: 'Another post' } ];
return new Response(JSON.stringify(posts), { headers: { 'Content-Type': 'application/json' } });};
export const POST: RequestHandler = async ({ request }) => { const data = await request.json();
if (!data.title || !data.content) { return new Response(JSON.stringify({ error: 'Missing fields' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); }
// Save to database here const newPost = { id: 3, ...data };
return new Response(JSON.stringify(newPost), { status: 201, headers: { 'Content-Type': 'application/json' } });};Form Actions with Server-Side Handling
<script> import { enhance } from '$app/forms'; let message = '';
function handleResult({ result }) { if (result.type === 'success') { message = 'Message sent successfully!'; } else if (result.type === 'failure') { message = 'Failed to send message.'; } }</script>
<svelte:head> <title>Contact Us</title></svelte:head>
<div class="form-container"> <h1>Contact Us</h1> {#if message} <div class="message">{message}</div> {/if}
<form method="POST" use:enhance={handleResult}> <input type="text" name="name" placeholder="Your Name" required /> <input type="email" name="email" placeholder="Your Email" required /> <textarea name="message" placeholder="Your Message" required /> <button type="submit">Send Message</button> </form></div>
<style> .form-container { max-width: 500px; margin: 0 auto; padding: 2rem; }
input, textarea { width: 100%; padding: 0.5rem; margin-bottom: 1rem; border: 1px solid #ccc; border-radius: 4px; }
button { padding: 0.5rem 1rem; background-color: #0066cc; color: white; border: none; border-radius: 4px; cursor: pointer; }</style>import type { Actions } from '@sveltejs/kit';
export const actions: Actions = { default: async ({ request }) => { const data = await request.formData(); const name = data.get('name'); const email = data.get('email'); const message = data.get('message');
if (!name || !email || !message) { return { success: false }; }
// Process form submission (send email, save to database, etc.) try { // Example: send email await fetch('https://api.example.com/send-email', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, email, message }) });
return { success: true }; } catch (error) { return { success: false }; } }};Project Structure
A typical SvelteKit project has this structure:
my-sveltekit-app/├── src/│ ├── routes/│ │ ├── +layout.svelte│ │ ├── +page.svelte│ │ ├── +page.server.ts│ │ ├── about/│ │ │ └── +page.svelte│ │ ├── posts/│ │ │ ├── +page.svelte│ │ │ ├── +page.server.ts│ │ │ └── [id]/│ │ │ └── +page.svelte│ │ ├── api/│ │ │ └── posts/│ │ │ └── +server.ts│ │ └── contact/│ │ ├── +page.svelte│ │ └── +page.server.ts│ ├── lib/│ │ ├── components/│ │ └── utils.ts│ ├── app.html│ └── app.css├── static/│ └── favicon.png├── .env├── .env.example├── svelte.config.js├── package.json├── tsconfig.json└── vite.config.tsSvelteKit Adapters & Configuration
SvelteKit uses adapters to build for different platforms. For Klutch.sh, use the Node.js adapter:
Install and Configure Node Adapter
npm install --save-dev @sveltejs/adapter-nodeUpdate your svelte.config.js:
import adapter from '@sveltejs/adapter-node';import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
export default { preprocess: vitePreprocess(), kit: { adapter: adapter({ out: 'build', precompress: false, envPrefix: '' }) }};Deploying Without a Dockerfile
Klutch.sh uses Nixpacks to automatically detect and build your SvelteKit application. This is the simplest deployment option that requires no additional configuration files.
-
Test your SvelteKit app locally to ensure it builds and runs correctly:
Terminal window npm run buildnpm run preview - Push your SvelteKit application to a GitHub repository with all source code, configuration files, and lock files included.
- Log in to your Klutch.sh dashboard.
- Create a new project and give it a name (e.g., "My SvelteKit App").
-
Create a new app with the following configuration:
- Repository - Select your SvelteKit GitHub repository and the branch to deploy
- Traffic Type - Select HTTP (for web applications serving HTTP traffic)
- Internal Port - Set to 3000 (the default port for SvelteKit applications)
- Region - Choose your preferred region for deployment
- Compute - Select appropriate compute resources for your application
- Instances - Start with 1 instance for testing, scale as needed
- Environment Variables - Add any required environment variables (API keys, database URLs, etc.)
If you need to customize the build or start commands, set these Nixpacks environment variables:
BUILD_COMMAND: Override the default build command (e.g.,npm run build)START_COMMAND: Override the default start command (e.g.,node build)
- Click "Create" to deploy. Klutch.sh will automatically detect your Node.js/SvelteKit project, install dependencies, build your application, and start it.
- Once deployed, your app will be available at a URL like `example-app.klutch.sh`. Test it by visiting the URL in your browser.
Deploying With a Dockerfile
If you prefer more control over the build and runtime environment, you can use a Dockerfile. Klutch.sh will automatically detect and use any Dockerfile in your repository’s root directory.
-
Create a `Dockerfile` in your project root:
# Multi-stage build for optimized SvelteKit deploymentFROM node:18-bullseye-slim AS builderWORKDIR /app# Copy package filesCOPY package*.json ./# Install dependenciesRUN npm ci# Copy source codeCOPY . .# Build SvelteKit applicationRUN npm run build# Production stageFROM node:18-bullseye-slimWORKDIR /app# Copy package filesCOPY package*.json ./# Install production dependencies onlyRUN npm ci --production# Copy built application from builderCOPY --from=builder /app/build ./build# Set environment variablesENV NODE_ENV=productionENV PORT=3000# Expose portEXPOSE 3000# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \CMD node -e "require('http').get('http://localhost:3000', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"# Start the applicationCMD ["node", "build"]
-
Create a `.dockerignore` file to exclude unnecessary files from the Docker build:
node_modulesnpm-debug.log.git.gitignoreREADME.md.env.env.local.vscode.idea.DS_Storebuild.svelte-kit
- Push your code (with Dockerfile and .dockerignore) to GitHub.
-
Follow the same deployment steps as the Nixpacks method:
- Log in to Klutch.sh
- Create a new project
- Create a new app pointing to your GitHub repository
- Set the traffic type to HTTP and internal port to 3000
- Add any required environment variables
- Click “Create”
Klutch.sh will automatically detect your Dockerfile and use it to build and deploy your application.
- Your deployed app will be available at `example-app.klutch.sh` once the build and deployment complete.
Environment Variables & Configuration
SvelteKit applications use environment variables for configuration. Set these in the Klutch.sh dashboard during app creation or update them afterward.
Common Environment Variables
# Server configurationPORT=3000NODE_ENV=production
# API configurationPUBLIC_API_URL=https://api.example.comVITE_API_URL=https://api.example.com
# Database (if using a backend database)DATABASE_URL=postgresql://user:password@host:5432/sveltekit_prod
# AuthenticationSESSION_SECRET=your_secret_session_key_hereAUTH_TOKEN=your_auth_token
# Third-party servicesSTRIPE_PUBLIC_KEY=pk_live_xxxxxSTRIPE_SECRET_KEY=sk_live_xxxxxSENDGRID_API_KEY=SG.xxxxx
# Environment-specific settingsLOG_LEVEL=infoENABLE_DEBUG=falseUsing Environment Variables in SvelteKit
import { env } from '$env/dynamic/private';import { PUBLIC_API_URL } from '$env/static/public';
export const getApiUrl = () => { return PUBLIC_API_URL || 'https://api.example.com';};
export const getSessionSecret = () => { const secret = env.SESSION_SECRET; if (!secret) { throw new Error('SESSION_SECRET environment variable is not set'); } return secret;};
export const isDevelopment = () => { return process.env.NODE_ENV === 'development';};
export const isProduction = () => { return process.env.NODE_ENV === 'production';};<!-- Use public variables in components --><script> import { PUBLIC_API_URL } from '$env/static/public';</script>
<p>API URL: {PUBLIC_API_URL}</p>Server Routes & API Endpoints
SvelteKit makes it easy to build API endpoints and server-side functionality:
Creating API Routes
import { json } from '@sveltejs/kit';import type { RequestHandler } from '@sveltejs/kit';
export const GET: RequestHandler = async () => { const users = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' } ];
return json(users);};
export const POST: RequestHandler = async ({ request }) => { const data = await request.json();
if (!data.name || !data.email) { return json( { error: 'Name and email are required' }, { status: 400 } ); }
// Save user to database const newUser = { id: 3, ...data };
return json(newUser, { status: 201 });};Using Endpoints in Components
<script> import { onMount } from 'svelte'; let users = []; let loading = true; let error = null;
onMount(async () => { try { const response = await fetch('/api/users'); if (!response.ok) throw new Error('Failed to fetch users'); users = await response.json(); } catch (err) { error = err.message; } finally { loading = false; } });</script>
<svelte:head> <title>Users</title></svelte:head>
{#if loading} <p>Loading...</p>{:else if error} <p>Error: {error}</p>{:else} <ul> {#each users as user (user.id)} <li>{user.name} - {user.email}</li> {/each} </ul>{/if}Form Actions & Progressive Enhancement
SvelteKit’s form actions provide server-side handling with progressive enhancement:
import type { Actions } from '@sveltejs/kit';import { redirect } from '@sveltejs/kit';
export const actions: Actions = { login: async ({ request, cookies }) => { const data = await request.formData(); const email = data.get('email'); const password = data.get('password');
// Validate input if (!email || !password) { return { success: false, message: 'Email and password required' }; }
// Authenticate user try { const response = await fetch('https://api.example.com/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) });
if (!response.ok) { return { success: false, message: 'Invalid credentials' }; }
const { token } = await response.json();
// Set session cookie cookies.set('session', token, { path: '/', httpOnly: true, secure: true, sameSite: 'strict', maxAge: 60 * 60 * 24 * 7 // 7 days });
throw redirect(302, '/dashboard'); } catch (error) { return { success: false, message: 'Login failed' }; } }};Troubleshooting
Build Failures
Problem - Deployment fails during the build phase
Solution:
- Verify your SvelteKit app builds locally:
npm run build - Ensure all dependencies are properly listed in
package.json - Check for TypeScript errors:
npm run check(if configured) - Verify that the adapter is installed and configured
- Check build logs in the Klutch.sh dashboard for specific errors
- Ensure
svelte.config.jsis correctly configured with the Node adapter
Application Won’t Start
Problem - App shows as unhealthy after deployment
Solution:
- Verify the app starts locally:
npm run preview - Check that port 3000 is configured correctly in Klutch.sh
- Verify all required environment variables are set
- Check application logs in the Klutch.sh dashboard
- Ensure the built application is being deployed (check build directory)
- Verify that the
builddirectory was created during build process
Memory Issues
Problem - App crashes with out of memory errors
Solution:
- Upgrade to a larger compute tier in Klutch.sh
- Optimize component rendering (avoid expensive computations)
- Implement lazy loading for large datasets
- Monitor memory usage during development
- Check for memory leaks in server routes
- Consider implementing caching strategies
Slow Builds
Problem - Build takes longer than expected
Solution:
- Use the multi-stage Dockerfile to reduce final image size
- Cache dependencies properly in Docker
- Optimize imports and tree-shake unused code
- Check for large dependencies that can be replaced
- Use
npm ciinstead ofnpm installfor faster, reproducible builds - Enable SvelteKit’s precompression during build
Performance Issues
Problem - App runs slowly in production
Solution:
- Enable compression for HTTP responses
- Use CDN for static assets
- Implement proper caching headers
- Optimize images and assets
- Profile performance with browser DevTools
- Use SvelteKit’s built-in optimization features
- Consider implementing service workers for offline functionality
Resources
- SvelteKit Official Website
- SvelteKit Documentation
- SvelteKit Routing Guide
- SvelteKit Form Actions
- SvelteKit Page Options & Rendering
- Nixpacks Documentation
- Klutch.sh Dashboard
Summary
Deploying a SvelteKit application on Klutch.sh is straightforward whether you choose Nixpacks or Docker. SvelteKit’s modern architecture with server-side rendering, API routes, form actions, and progressive enhancement makes it ideal for building fast, interactive web applications. Both deployment methods provide reliable, scalable hosting for your SvelteKit apps. Start with Nixpacks for simplicity, or use Docker for complete control over your build environment. With SvelteKit’s excellent developer experience and Klutch.sh’s scalable infrastructure, you can deploy production-ready applications that deliver exceptional performance and user experience at scale.