Skip to content

Server & API

A +server.js file is a route with no UI — a standalone HTTP endpoint. Export functions named for the HTTP method; each returns a Response. Use it for JSON APIs, webhooks, file downloads, or anything a non-browser client calls.

src/routes/api/posts/+server.js
import { json, error } from '@sveltejs/kit';
export async function GET({ url }) {
const page = Number(url.searchParams.get('page') ?? '1');
return json(await getPosts(page)); // json() sets the header + serializes
}
export async function POST({ request }) {
const body = await request.json();
if (!body.title) error(400, 'title required'); // throw a typed HTTP error
return json(await createPost(body), { status: 201 });
}

Endpoint vs form action: use a form action when a page’s own form submits to the server (it integrates with use:enhance and the form prop). Use a +server.js endpoint for a reusable API consumed by fetch, a mobile app, or a third party.

src/hooks.server.js exports handle, which runs on every request before it reaches a route — the place for authentication, logging, and populating locals.

src/hooks.server.js
export async function handle({ event, resolve }) {
const token = event.cookies.get('session');
event.locals.user = token ? await getUser(token) : null; // available to load/actions
return resolve(event); // continue to the route
}

Whatever you set on event.locals is available in every server load and action for that request (via locals) — this is how the current user flows through the app.

flowchart LR
  req["incoming request"] --> handle["hooks: handle()
set locals.user"]
  handle --> route["route: load / action / +server"]
  route --> resp["response"]
A request passes through handle, then the route

Each route can choose how it renders, with page options exported from +page.js/+page.server.js:

  • export const prerender = true — render to a static file at build time (great for pages that are the same for everyone).
  • export const ssr = false — skip server rendering (client-only page).
  • export const csr = false — ship no client JS (fully static output for that page).

Finally, an adapter (set in svelte.config.js) packages your built app for a target platform:

  • adapter-auto — detects common platforms (the default in a new project).
  • adapter-node — a standalone Node server.
  • adapter-cloudflare — a Cloudflare Worker/Pages.
  • adapter-static — a fully prerendered static site (no server needed).

You choose the adapter for where you deploy; the same app code runs across them.

What is a `+server.js` file?
What does `handle` in `hooks.server.js` do?
How do you make a single route render to a static file at build time?
What does an adapter do?