Back to Blog
Tutorial8 min read2026-07-06

How to Deploy a Svelte SPA

Deploy a Svelte single-page application to production: the Vite build, SPA fallback routing, environment variables at build time, custom domains with SSL, and continuous deploys from Git.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

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 build

which 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.

  1. 1Push your Svelte/Vite project to GitHub.
  2. 2Create a static site in the dashboard and connect the repo.
  3. 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.
  4. 4Configure SPA fallback so unmatched routes serve index.html, this is what makes client-side routing and deep links work.
  5. 5Add any VITE_-prefixed build-time variables in the dashboard before building.
  6. 6The build runs in a pandastack.ai microVM and publishes to the edge with automatic SSL.
SettingValue
Build commandnpm run build
Publish directorydist
Install commandnpm install (override for yarn/pnpm/bun)
SPA fallbackserve index.html for unmatched routes
Env varsVITE_* (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

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also