PrevelteKit Documentation

(Server Pre-Rendered)

Quick Start

Make sure you have node/npm installed. Here is a minimalistic example:
mkdir -p preveltekit/src && cd preveltekit
echo '{"devDependencies": {"preveltekit": "^1.2.18"},"dependencies": {"svelte": "^5.39.11"},"scripts": {"dev": "preveltekit dev"}}' > package.json
npm install
echo '<script>let count = $state(0);</script><h1>Count: {count}</h1><button onclick={() => count++}>Click me</button>' > src/Index.svelte
npm run dev
# And open a browser with localhost:3000

Core Features

⚡ Single Page Application with Built-time Pre-rendering (SPAwBR)

PrevelteKit combines the best of SPA and build-time rendering with hydration approaches. Unlike traditional SSR that renders on each request, or pure SPA that shows blank pages initially, SPAwBR pre-renders your layout and static content at build time while maintaining full interactivity through hydration. This provides fast initial page loads with visible content, then progressive enhancement as JavaScript loads.

🎯 Simple Architecture

Built on a clear separation between frontend and backend. Your frontend is purely static assets (HTML/CSS/JS) that can be served from any CDN or web server, while data comes from dedicated API endpoints. No JavaScript runtime required for serving.

⚡ Lightning Fast Builds

Built on Rsbuild for builds in the range of hundreds of milliseconds. The system automatically handles:

  • TypeScript compilation and type checking
  • Asset optimization and bundling
  • CSS processing and minification
  • Pre-compression (Brotli, Zstandard, Gzip)

🔧 Development Workflow

Three modes available to suit your needs:

  • Development (npm run dev): Express server with fast rebuilds and live reloading
  • Staging (npm run stage): Production build with local preview server
  • Production (npm run build): Optimized build with pre-compression for deployment

Rendering Comparison

Rendering TypeInitial LoadAfter Script
SSR (classic SSR / Next.js / Nuxt)SSR Initial
User sees content instantly
(rendered on each request)
SSR After
User sees content instantly
(no additional loading)
SPA (React App / pure Svelte)SPA Initial
User sees white page or spinner
(no content until JS loads)
SPA Loaded
User sees full content
(after script execution)
SPA + Build-time Pre-Rendering (this approach)SPAwBR Initial
User sees layout and static content
(pre-rendered at build time)
SPAwBR Hydrated
User sees interactive content
(hydrated with full functionality)

SPAwBR Development

🔍 Detecting Build-time Pre-rendering

PrevelteKit uses window.__isBuildTime to indicate when code is running during build-time pre-rendering. This is crucial for handling client-side-only code like API calls and intervals.

// Basic detection
let renderInfo = "Client Rendered";
if (window?.__isBuildTime) {
    renderInfo = "Server Pre-Rendered";
}

🔄 Handling Client-Side Operations

PrevelteKit automatically handles fetch requests during build-time pre-rendering. Fetch calls made during pre-rendering will timeout after 5 seconds, allowing your components to render with loading states. You no longer need to wrap fetch calls in window.__isBuildTime checks.

// Fetch automatically handled during pre-rendering
let pricePromise = $state(fetchBitcoinPrice());

// Use Svelte's await block for clean handling
{#await pricePromise}
    <p>Loading...</p>
{:then data}
    <p>{data}</p>
{:catch error}
    <p>Error: {error.message}</p>
{/await}

When to still use build-time checks:

  • Browser APIs (localStorage, sessionStorage, geolocation)
  • DOM manipulation that shouldn't happen during pre-rendering
  • Third-party scripts that expect a real browser environment

Configuration

PrevelteKit uses rsbuild.config.ts for configuration with sensible defaults. To customize settings, create an rsbuild.config.ts file in your project - it will merge with the default configuration.

The framework provides fallback files (index.html and index.ts) from the default folder when you don't supply your own. Once you add your own files, PrevelteKit uses those instead, ignoring the defaults.

Client-Side Routing

PrevelteKit includes a built-in routing system that handles navigation between different pages in your application. The router uses pattern matching to determine which component to render based on the current URL path.

🧭 Route Configuration

Define your routes as an array of route objects, each specifying a path pattern, the component to render, and the static HTML file name:

const routes: Routes = {
     dynamicRoutes: [
         {
             path: "*/doc",
             component: Documentation
         },
         {
             path: "*/example",
             component: Example
         },
         {
             path: "*/",
             component: Landing
         }
     ],
     staticRoutes: [
         {
             path: "/doc",
             htmlFilename: "doc.html"
         },
         {
             path: "/example",
             htmlFilename: "example.html"
         },
         {
             path: "/",
             htmlFilename: "index.html"
         }
     ]
 };

 <Router routes>

🔍 Path Patterns

PrevelteKit supports flexible path patterns for routing:

  • Wildcard prefix (*/path): Matches any single segment before the path (e.g., */doc matches /doc and /any/doc)
  • Root wildcard (*/): Matches the root path and single-segment paths
  • Exact paths (/about): Matches the exact path only
  • Parameters (/user/:id): Captures URL segments as parameters

🔗 Navigation

Use the route action for client-side navigation that updates the URL without page reloads:

import { route } from 'preveltekit';

    <a use:link href="doc">Documentation</a>
    <a use:link href="example">Example</a>

📄 Static File Mapping & Hybrid Routing

The staticRoutes array configuration serves a dual purpose in PrevelteKit's hybrid routing approach:

htmlFilename: "doc.html"  // Generates dist/doc.html at build time

Static Generation: During the build process, PrevelteKit generates actual HTML files in your dist/ folder for each route:

  • dist/index.html - Pre-rendered root route
  • dist/doc.html - Pre-rendered documentation page
  • dist/example.html - Pre-rendered example page

Dynamic Routing: Once the application loads, the same route configuration enables client-side navigation between pages without full page reloads. This provides:

  • Fast initial page loads from pre-rendered static HTML
  • Instant navigation between routes via client-side routing
  • SEO benefits from static HTML while maintaining SPA functionality

This hybrid approach means users get static HTML files for direct access (bookmarks, search engines) and dynamic routing for seamless navigation within the application.

⚙️ Route Matching Priority

Routes are matched based on specificity, with more specific patterns taking precedence:

  1. Exact path matches (highest priority)
  2. Parameter-based routes
  3. Wildcard patterns (lowest priority)

Always place more specific routes before general wildcard routes in your configuration to ensure proper matching behavior.

Docker Support

Development environment:

docker build -f Dockerfile.dev . -t preveltekit-dev
docker run -p3000:3000 -v./src:/app/src preveltekit-dev

Production build:

docker build . -t preveltekit
docker run -p3000:3000 preveltekit

Architecture Philosophy

PrevelteKit emphasizes static-first architecture with clear separation between frontend and backend:

  • Frontend: Pure static assets (HTML/CSS/JS) served from any web server or CDN
  • Backend: Dedicated API endpoints for data, can be built with any technology
  • Deployment: No JavaScript runtime required - just static files

This approach offers compelling simplicity compared to full-stack meta-frameworks:

  • Deploy anywhere (GitHub Pages, S3, any web server)
  • Predictable performance with no server processes to monitor
  • Easier debugging with clear boundaries
  • Freedom to choose your backend technology

Deployment

The production build generates static files with pre-compressed variants:

  • Standard files (.js, .css, .html)
  • Brotli compressed (.br)
  • Gzip compressed (.gz)
  • Zstandard compressed (.zst)

Deploy to any static hosting or web server. The pre-compressed files enable optimal performance when served with appropriate web server configuration.

Why PrevelteKit?

While SvelteKit provides comprehensive capabilities, PrevelteKit focuses on a minimalistic solution for build-time pre-rendering. With less than 500 lines of code, it's essentially glue code for Svelte, Rsbuild, and jsdom - perfect for projects that need fast initial loads without the complexity of full JavaScript infrastructure for the frontend deployment.

PrevelteKit serves as a starting point for projects that need pre-rendered content without the overhead of a full meta-framework, following a "convention over configuration" approach.