Svelte produces some of the smallest, fastest frontend bundles around because it compiles components to vanilla JavaScript at build time, there's no virtual DOM runtime shipped to the browser. A Svelte single-page application (SPA) built with Vite compiles to static files you serve from a CDN. The deployment is simple, with one classic gotcha: SPA fallback routing. This guide covers it.
How a Svelte SPA builds
A Vite-based Svelte project builds with:
npm run buildwhich runs vite build and outputs static assets to dist/, an index.html, hashed JS and CSS bundles, and your assets. There's no server; the browser loads index.html and the JavaScript takes over routing client-side. This is what makes an SPA cheap to host: it's static files plus client-side logic.
Note the distinction: this guide is about a Svelte SPA (client-side rendered). If you're using SvelteKit with server-side rendering, that's a different deployment (a Node server or an adapter), but a pure SPA, including SvelteKit with the static adapter, is just static files.
The SPA fallback gotcha
Here's the single most important thing about deploying any SPA, Svelte included. Your app does client-side routing: navigating to /dashboard is handled by JavaScript in the browser, not by a real file at /dashboard/index.html. That works fine when the user navigates within the app. But if they refresh the page on /dashboard, or paste that URL directly, the server gets a request for /dashboard, finds no such file, and returns a 404.
The fix is SPA fallback routing: configure the host to serve index.html for any unmatched route, so the browser loads the app and the client-side router resolves the path. Without this, deep links and refreshes break, the most common SPA deployment bug by far.
Build-time environment variables
Vite exposes environment variables prefixed with VITE_ to your client code at build time:
const apiUrl = import.meta.env.VITE_API_URL;These are baked into the bundle when you build, not read at runtime. So configure them before the build, and remember they're public, anything in a VITE_-prefixed variable ships to the browser, so never put secrets there. Use them for things like the API base URL or a public analytics key.
Deploying on PandaStack
A Svelte SPA is a static site, so it deploys as a static site, building in a fast microVM and serving from the edge.
- 1Push your Svelte/Vite project to GitHub.
- 2Create a static site in the dashboard and connect the repo.
- 3PandaStack auto-detects the framework (Vite/Svelte). It identifies the build command (
npm run build) and the publish directory (dist). Override the install command for yarn, pnpm, or bun if needed. - 4Configure SPA fallback so unmatched routes serve
index.html, this is what makes client-side routing and deep links work. - 5Add any
VITE_-prefixed build-time variables in the dashboard before building. - 6The build runs in a pandastack.ai microVM and publishes to the edge with automatic SSL.
| Setting | Value |
|---|---|
| Build command | npm run build |
| Publish directory | dist |
| Install command | npm install (override for yarn/pnpm/bun) |
| SPA fallback | serve index.html for unmatched routes |
| Env vars | VITE_* (public, build-time) |
Continuous deploys
Every push to your default branch rebuilds and redeploys. For a frontend in active development, that means merge a PR and the new version is live minutes later. Deploy history lets you roll back instantly if a build ships a regression.
Custom domains and SSL
Add your domain in the dashboard and point DNS at the provided target. SSL is issued and renewed automatically. Your SPA can then call your API over HTTPS without mixed-content warnings.
Performance
Svelte's compiled output is already small, and serving it from the edge means fast first loads worldwide with no cold starts. A few tips to keep it fast:
- Let Vite code-split routes so users only download what they need.
- Use hashed filenames (Vite does this by default) for long-lived caching.
- Compress and lazy-load images.
The combination of Svelte's tiny bundles and edge static hosting is hard to beat for frontend performance.
Free tier fit
A Svelte SPA is an ideal free-tier workload. The free tier includes static sites with 100GB bandwidth and 300 build minutes per month, more than enough for most frontends. There's no scale-to-zero cold-start concern for static content, the files are always served from the edge. If you run many frontends or build very frequently, the Pro tier offers unlimited static sites and more build minutes. A common pattern: deploy your Svelte SPA as a static site and your API as a separate container app, both from the same dashboard.
Common pitfalls
- No SPA fallback, refreshing a deep link returns 404.
- Secrets in
VITE_variables, they ship to the browser; keep them public-only. - Wrong publish directory, Vite outputs to
dist. - Expecting runtime env vars, Vite bakes them in at build time.
References
- Svelte documentation: https://svelte.dev/docs
- Vite static deployment guide: https://vite.dev/guide/static-deploy
- Vite environment variables: https://vite.dev/guide/env-and-mode
- SvelteKit static adapter: https://svelte.dev/docs/kit/adapter-static
- SPA fallback explanation: https://vite.dev/guide/build#building-for-production
A Svelte SPA deploys as fast static files, the one thing to get right is SPA fallback routing so deep links and refreshes work. Publish your Svelte app with automatic SSL and Git-based deploys on PandaStack's free tier: https://dashboard.pandastack.io