SvelteKit on Easel
Deploy SvelteKit applications to Easel with SSR, streaming, prerendering, form actions, hooks, and API endpoints.
Easel runs SvelteKit applications built with the standard Vercel adapter.
Prerendered pages and client assets go to the CDN, and server-rendered pages,
load functions, form actions, hooks, and +server endpoints run in Easel
Functions with streaming.
At a glance
| Support level | Production-ready |
| Rendering | Static, SSR, streaming, and client-side rendering |
| Server runtime | Node.js |
| Required adapter | @sveltejs/adapter-vercel |
| Automatic detection | Yes |
| Most recently tested with | SvelteKit 2.70.x |
Deploy a SvelteKit application
Install the Vercel adapter:
Then select it in svelte.config.js:
The adapter produces the deployable output Easel reads. It doesn't deploy to
Vercel or need a Vercel account. Don't use adapter-auto. It picks an adapter
from the build environment, so the output isn't reproducible.
Create a project from your Git repository or deploy with the CLI:
Easel detects SvelteKit and runs your build script or vite build. Install command, build command, root directory, and Node.js version
live in build configuration.
What Easel deploys
| SvelteKit output | Easel resource |
|---|---|
Files in static | CDN assets |
| Client JavaScript and CSS | CDN assets |
| Prerendered pages | CDN assets |
| Server-rendered pages | Easel Functions |
Server load functions | Easel Functions |
| Form actions | Easel Functions |
+server endpoints | Easel Functions |
| Server hooks | Easel Functions |
| Redirects and route metadata | Easel request routing |
By default the adapter packages every dynamic route into one shared server function, and SvelteKit routes requests inside it. Prerendered routes drop out of that bundle.
The adapter can also split routes into separate functions. Keep the default unless you need to isolate a heavy endpoint or give it different settings, and verify a split build in a preview deployment.
Supported features
| Feature | Support | Notes |
|---|---|---|
| Server-side rendering | Supported | Dynamic routes run in Easel Functions |
| Prerendering | Supported | Includes prerender = "auto" with entries |
| Client-side rendering | Supported | Set with ssr and csr page options |
| Streaming server loads | Supported | Returned promises stream as they resolve |
| Streaming endpoints | Supported | ReadableStream responses aren't buffered |
| Universal and server load | Supported | Follow SvelteKit's normal lifecycle |
| Form actions | Supported | Includes progressive enhancement with use:enhance |
| API endpoints | Supported | +server handlers |
| Server hooks | Supported | handle, handleFetch, and handleError |
| Cookies | Supported | Standard cookies API |
| Route parameters, groups | Supported | Includes optional, rest, and matched parameters |
| Environment modules | Supported | $env/static/* and $env/dynamic/* |
| Server instrumentation | Supported | Included when emitted by the adapter |
| Base paths, trailing slash | Supported | kit.paths.base and the trailingSlash option |
| Service workers | Supported | Built as static assets and served from the CDN |
| Adapter infrastructure options | Partial | See Adapter options |
Rendering
Pages are server-rendered by default. A server load function can read private
environment variables, cookies, and locals, then return data to the page:
The load function and the page render run in an Easel Function.
Prerendering
Export prerender from a page or layout to generate it at build time.
Prerendered pages deploy as static files and don't invoke a function:
Child routes can override the inherited value with prerender = false. Use
"auto" with an entries function to prerender known parameter values while
other values still render on the server:
Client-side rendering
Set ssr = false in +page.ts to render a route only in the browser, or
csr = false to ship static HTML without hydration.
Streaming
A server load function can return promises that resolve after the initial page data:
Render the streamed value with {#await data.reviews} in the page. Easel
forwards the response as SvelteKit produces it instead of waiting for every
promise to settle.
Once streaming starts, status and headers are fixed. Don't redirect or call
setHeaders from inside a promise that resolves later. Streamed data needs
browser JavaScript. Without it, the browser waits for the full response.
Form actions
Form actions run in the server function:
A plain <form method="POST"> works without JavaScript. Add use:enhance from
$app/forms to submit without a full-page reload.
API endpoints
+server files become HTTP endpoints:
Handlers can return any standard Response, including redirects, files,
Server-Sent Events, and ReadableStream bodies. Long-lived responses stay
subject to the function's maximum duration
(limits).
Hooks
Server hooks run inside the server function. Use handle to authenticate
requests, populate event.locals, or change responses:
locals is then available to server loads, actions, and endpoints. Use
handleFetch to change server-side requests made through SvelteKit's fetch.
SvelteKit's cookies API works in loads, actions, endpoints, and hooks. Keep
session state in a database or shared store, not function memory.
Cache control
Set cache headers from a server load with setHeaders, or directly on an
endpoint's Response:
The Easel CDN caches eligible responses from these headers. Don't mark personalized or authenticated responses public. See Caching.
Environment variables
SvelteKit splits variables by visibility and by when they're read:
| Module | Visibility | Resolved |
|---|---|---|
$env/static/private | Server only | Build time, inlined |
$env/static/public | Browser, PUBLIC_ prefix | Build time, inlined |
$env/dynamic/private | Server only | Request time, from Easel |
$env/dynamic/public | Browser, PUBLIC_ prefix | Request time, from Easel |
Static values need a new deployment after they change. SvelteKit blocks
private modules from browser code. Recent SvelteKit 2 releases can opt into
the explicit $app/env/private and $app/env/public modules declared in
src/env.ts. Easel supplies the same values either way.
Set values per environment in Environment variables.
Adapter options
Easel reads the adapter's functions, static and prerendered assets, and
routing config. Project settings stay authoritative for function memory, CPU,
and scaling. Route maxDuration is honored when the adapter emits it. Don't
rely on the adapter's other memory or region options. See
Function configuration.
Build-time image processing works because it emits ordinary static assets. Test runtime image plugins in a preview deployment, since they may depend on provider-specific APIs.
Project configuration
| Setting | Default |
|---|---|
| Install command | Detected from the package manager |
| Build command | Package script or vite build |
| Output directory | Read from the adapter output |
| Development command | Package script or vite dev |
In a monorepo, set the root directory to the folder that holds the app's
package.json and svelte.config.js.
Local development
Keep using npm run dev. The Vite dev server runs routing, SSR, loads,
actions, hooks, and endpoints locally. Use a
preview deployment to check adapter output, function
packaging, streaming, and CDN caching before production.
Known limitations
SvelteKit runs in Easel Functions, which have no WebSockets, an ephemeral filesystem, and no work after the response unless you register it. See Function runtime and Background work.
Vercel-specific adapter options aren't reproduced. Configure infrastructure in Easel project settings.
Troubleshooting
Easel doesn't find a server application
Confirm that @sveltejs/adapter-vercel is installed and selected in
svelte.config.js, not adapter-auto.
The deployment contains only static files
Check whether the root layout exports prerender = true. Fully prerendered
routes leave the server bundle.
A route fails during prerendering
A prerendered route can't read cookies, headers, or other request data. Set
prerender = false for it or move the request-dependent work elsewhere.
A dynamic route is missing from the prerendered output
SvelteKit needs to know which parameter values to generate. Export entries,
or link to the route from another prerendered page.
An environment variable is undefined
Check that you import from the right module (static or dynamic, private or
public). Browser-visible variables need the PUBLIC_ prefix. Static values
need a new deployment after a change.
A streamed value never appears early
Return the promise from the server load instead of awaiting it. Headers and redirects must happen before streaming starts.
Compatibility policy
Easel's SvelteKit baseline is the version under At a glance. Test upgrades in a preview deployment, as described in the compatibility policy.