SvelteKit
Fly.Website.SvelteKit deploys a
SvelteKit app to Fly. It builds the
app with SvelteKit’s own Vite pipeline and an in-memory Node adapter.
Client assets and prerendered pages bake into the Machine image and
are served first; dynamic routes run in the kit handler on port 3000.
Alchemy creates a Fly.App if you omit app, a Fly.Service on
that App, and a shared IPv4 so https://{app}.fly.dev answers. Your
vite.config.ts loads natively; there is no svelte.config.js to
write (kit v3 dropped it) and no adapter to install.
Install
Section titled “Install”The build integration is not bundled with alchemy. Install
@alchemy.run/frontend-frameworks; the resource loads its
/sveltekit and /sveltekit/node exports from your project at
deploy time. It is only used at build time, so a dev dependency is
enough:
bun add -d @alchemy.run/frontend-frameworksnpm install -D @alchemy.run/frontend-frameworkspnpm add -D @alchemy.run/frontend-frameworksyarn add -D @alchemy.run/frontend-frameworksConfigure SvelteKit
Section titled “Configure SvelteKit”Your project’s vite.config.ts loads natively — your Vite plugins
and the kit options in your sveltekit(...) call all apply as usual.
Alchemy injects its Node adapter (replacing any adapter you declare,
with a warning), so a fresh SvelteKit project deploys as-is.
Deploy-specific kit overrides can also be passed via the kit prop,
which merges over your sveltekit(...) options — see
Kit options below. A project without a
vite.config.* works too: the resource falls back to a fully
programmatic build.
Declare the Website
Section titled “Declare the Website”Declare the site as a module-level const (rather than inline in the Stack):
import * as Fly from "alchemy/Fly";
export const Website = Fly.Website.SvelteKit("Website");Omit app to create a Fly.App under the site namespace. Pass an
existing App to share it with other resources.
Add it to the Stack
Section titled “Add it to the Stack”Yield the site from your Stack and return its URL:
import * as Alchemy from "alchemy";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "MySvelteKitSite", { providers: Fly.providers(), state: Alchemy.localState(), }, Effect.gen(function* () { const site = yield* Website; return { url: site.url }; }),);Routes with export const prerender = true are baked into the image
and served as static files first; server routes (+server.ts) and
server load functions run in the kit handler on the Machine.
Add environment variables
Section titled “Add environment variables”Process environment is a top-level env map:
export const Website = Fly.Website.SvelteKit("Website", { env: { GREETING: "Hello from alchemy", API_BASE: "https://api.example.com", },});The values are copied onto process.env before the build (and the
dev server) and onto the Machine at deploy time, so server code
reads the same keys in both modes.
Read the environment in server code
Section titled “Read the environment in server code”The Kit server runs in Node on the Machine, so server routes read
the environment from process.env (or kit’s $env/dynamic/private,
which is initialized from it):
export const load = () => { return { greeting: process.env.GREETING ?? "hello" };};Kit options
Section titled “Kit options”Since kit v3 there is no svelte.config.js — kit options live in the
sveltekit(...) call in your vite.config.ts, which loads natively:
import { sveltekit } from "@sveltejs/kit/vite";import tailwindcss from "@tailwindcss/vite";import { defineConfig } from "vite";
export default defineConfig({ plugins: [ tailwindcss(), sveltekit({ alias: { $lib: "src/lib" }, }), ],});The kit prop on the resource is a deploy-time override layer merged
over those options (the override wins). It must be JSON-serializable:
export const Website = Fly.Website.SvelteKit("Website", { kit: { paths: { base: "/docs" }, },});Don’t set kit.adapter — Alchemy injects its Node adapter (an
adapter declared in your sveltekit(...) call is replaced with a
warning).
Local dev
Section titled “Local dev”bun alchemy devalchemy dev runs SvelteKit’s own Vite dev server — Node SSR with
full HMR — instead of deploying; site.url is the local address and
no Fly resources are created (app, service, ip, and
certificate are undefined). Wrap the site in Alchemy.remote()
to deploy the live App even during dev.
Custom domain
Section titled “Custom domain”const site = yield* Fly.Website.SvelteKit("Web", { domain: "app.example.com",});Alchemy requests an ACME Fly.Certificate on the
App. Point DNS at the App first — v1 does not create records.
url becomes https://app.example.com.