Learn SvelteKit - API Routes & Back-end Integration
Episode 10 of 24

Learn SvelteKit - API Routes & Back-end Integration

This episode covers the server side of SvelteKit: defining endpoints with +server.js, consuming and exposing internal APIs, building authentication middleware for protected endpoints, and database integration with ORMs. You will build a cohesive back-end.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

SvelteKit is a full-stack framework: besides pages, it can also be a back-end API. Episode 10 covers the +server.js file that defines HTTP endpoints, how an application consumes its own internal APIs, and how to protect sensitive endpoints.

One application, one language, one deployment — this is the main advantage of making SvelteKit your back-end. You don't need a separate project for the API; endpoints live inside the same route structure as pages.

We'll build clean endpoints, secure them with middleware, and connect them to a database. By the end of the episode, you'll have a functional back-end tightly integrated with your front-end.

Server Routes and Endpoint Definitions

Creating Endpoints with +server.js

A +server.js file inside a route folder exports a handler per HTTP method: GET, POST, PUT, PATCH, DELETE, and OPTIONS. No component is rendered — the result is purely an HTTP response.

JSGET and POST endpoints
import { json } from "@sveltejs/kit";
 
export const GET = async ({ url }) => {
    const limit = Number(url.searchParams.get("limit") ?? 10);
    const daftar = await ambilData({ limit });
 
    return json(daftar);
};
 
export const POST = async ({ request }) => {
    const body = await request.json();
    const baru = await simpanData(body);
 
    return json(baru, { status: 201 });
};

The json helper from @sveltejs/kit creates a response with the correct Content-Type and automatic serialization. Handlers receive the same event as load functions, so params, url, request, cookies, and locals are all available.

Naming Conventions

The src/routes/api folder is the conventional place for API endpoints, though it's not mandatory — the structure fully follows routing. Endpoints can use dynamic segments, for example /api/artikel/[id] with a +server.js file in the [id] folder, so handlers can read params.id.

Consuming and Exposing Internal APIs

Using Your Own API with event.fetch

SvelteKit optimizes requests between routes: when a load function calls an internal endpoint with event.fetch, the request doesn't make a full network round trip — SvelteKit forwards it directly within the same process.

JSUsing an internal endpoint
export const load = async ({ fetch }) => {
    const res = await fetch("/api/artikel?limit=5");
    const artikel = await res.json();
 
    return { artikel };
};

Because it runs on the server, event.fetch follows the original request's cookies and headers. This means endpoints that read the session still work when called from a load function, without manually rebuilding headers.

Architectural Decisions

The "load function calls +server.js" pattern gives a clear separation between API data and views. But if both live in the same application, consider calling a shared function directly from src/lib/server — it's faster because it avoids the HTTP layer entirely. Choose +server.js when the endpoint is genuinely consumed by outsiders or other applications.

Authentication Middleware and Protected Endpoints

Middleware with Hooks

The handle hook runs for every request before the route is processed. This is the place for authentication middleware: read the session cookie, verify it, and store the result in event.locals.

JSAuth middleware in hooks.server.js
export const handle = async ({ event, resolve }) => {
    const session = event.cookies.get("session");
 
    if (session) {
        event.locals.user = await verifikasiSession(session);
    }
 
    return await resolve(event);
};

With this pattern, every handler in the application can access event.locals.user without repeating verification logic. A safe event.locals initialization is done by declaring the types in src/app.d.ts.

Protecting Endpoints

Sensitive endpoints check locals at the start of the handler:

JSProtected endpoint
export const GET = async ({ locals }) => {
    if (!locals.user) {
        throw error(401, "Autentikasi diperlukan");
    }
 
    return json({ user: locals.user });
};

Throwing error(401, ...) stops the handler and returns the appropriate status. For more granular access control, compare the user's role against the allowed roles, and use a single helper so the policy isn't scattered across many files.

Database and ORM Integration

Storing Structured Data

For applications with structured data and relations, ORMs like Prisma or Drizzle provide type safety and managed migrations. The database connection lives in src/lib/server and is only imported from server code.

JSDatabase query with Prisma
import prisma from "$lib/server/prisma";
 
export const load = async () => {
    const artikel = await prisma.artikel.findMany({
        orderBy: { createdAt: "desc" },
        take: 10
    });
 
    return { artikel };
};

Prisma in SvelteKit

Make sure the Prisma schema file and migrations are versioned. Run npx prisma migrate dev for development and npx prisma migrate deploy at deploy time. Since server code runs once per request, avoid creating a new connection each time — use the singleton pattern so a single Prisma instance is shared across the whole application.

Closing

Key takeaways:

  • The +server.js file defines endpoints per HTTP method and responds via json or Response.
  • event.fetch for calling internal endpoints, with cookies and headers forwarded.
  • The handle hook is the place for authentication middleware; results are stored in event.locals.
  • Sensitive endpoints check locals and throw error(401) when unauthenticated.
  • Database connections and ORMs live in src/lib/server so they never leak to the client.
  • Use the singleton pattern for the Prisma instance and run migrations with the right commands.

In the next episode we deepen user interaction: forms, validation, & interaction. You'll assemble form submission and validation flows, server-side validation with UI feedback, progressive enhancement with a no-JS fallback, plus file upload and multipart form handling.

Learn SvelteKit - API Routes & Back-end Integration | Learn SvelteKit