SvelteKit + Cloudflare — Create an API Endpoint

Ensure some of your web app’s code stays firmly on the server and never sees the client.

SvelteKitCloudflareCloudflare Workers

Deploying from SvelteKit to Cloudflare is an incredible way to create a frontend. But what about when you want more than client-side code? What if you have sensitive data you want kept from the client? Or large amounts of information you don’t want to embed? That’s where Cloudflare’s backend workers come in.

In this tutorial, I’ll explain how they work and show you how to leverage them.

Prerequisites + Background

The jumping in point for this article is the jumping off point of my last SvelteKit + Cloudflare article:

The Best Frontend — SvelteKit + Tailwind + Cloudflare

If you’re starting fresh, read that. Or if you can’t be bothered, here’s what you’ll need:

  1. A Cloudflare account.
  2. A GitHub account.
  3. A SvelteKit website, written in TypeScript, held in a repository on your GitHub account that’s connected to the Cloudflare CI/CD pipeline.
  4. A Cloudflare Pages deployment based on your GitHub repo, and deployed live.

If you’re interested, you can see my Cloudflare website here:

Level Up Your Coding Skills

What Are Cloudflare Workers?

Cloudflare Workers are serverless functions that run on Cloudflare’s edge network. They allow you to execute JavaScript (or TypeScript) closer to your users, without managing traditional servers. Workers can deliver web pages to the client, or handle sensitive operations, such as accessing a database or making API calls. SvelteKit puts server side code in backend Workers so the client cannot see the source.

Workers are perfect for:

  • Handling sensitive logic that shouldn’t be exposed to the client.
  • Processing large datasets without bloating the client-side bundle.
  • Interacting with external APIs or databases securely.
  • Customising responses based on user data or geolocation.

Background and prerequisites aside, let’s start building!

Step 1 — Create an API Route

You can create a backend function in SvelteKit by adding a route and placing a +server.ts file inside it. The code contained in this file will be run on the server-side only, keeping any important secrets safe from the client.

SvelteKit recommends using the route /api to store your server-side functions. To set this up, run the following from the root directory:

bash
mkdir src/routes/api

Next choose the name of your API endpoint by adding another folder:

bash
mkdir src/routes/api/<your-endpoint-name>

Add the +server.ts file with:

bash
touch src/routes/api/<your-endpoint-name>/+server.ts

There you have it, your new api route fully set up and ready to be filled with code.

Step 2 — Write Your API Function

An API route can handle all of the standard HTTP methods:

  • GET
  • POST
  • PUT
  • … (etc.)

To use one, you export it from the +server.ts file as a constant. Here are examples for GET, and POST that produce an array of numbers.

GET

For GET commands, you typically extract data from the search params before acting on it. Like so:

typescript
import { json } from '@sveltejs/kit';

You can see we parse the params out of the URL search parameters, then use them in our calculations before returning a numberArray as JSON. You can call this endpoint in Typescript like this:

typescript
async function getNumberArray() {
  const response = await fetch('/api/<your-endpoint-name>?min=1&max=100', {
   method: 'GET',
  });

  let data = await response.json();
  console.log(data.numberArray);
}

POST

For POST commands, your information is sent via the body, so you receive it like this:

typescript
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

// Request type for clarity
interface Request {
  min: number
  max: number
}

export const POST: RequestHandler = async ({ request }) => {
 const { min, max } = await request.json() as Request;

  const numberArray: number[] = [];
  for (let i = min; i < max; i++) {
    numberArray.push(i);
  }

 return json({numberArray}, {status: 200})
};

You can call the endpoint like this:

javascript
async function add() {
  const response = await fetch('/api/<your-endpoint-name>', {
    method: 'POST',
    body: JSON.stringify({ min: 1, max: 10}),
    headers: {
    'content-type': 'application/json'
    }
  });

  let data = response.json();
  console.log(data.numberArray);
}

Step 3 — Using Data

You can store data you want to use in the server-side function inside of src/lib like client-side data. As long as you don’t import it anywhere in a function that touches the frontend, your data will only ever be present on the server side.

This is great if you have reasonably static data and would rather bake it into your endpoint to reduce latency. This is what I have initially done for my full-stack gaming website.

Step 4 — Deploy and Test!

You can test in two ways. Firstly, you can test locally with:

bash
npm run dev

Which starts your site on https://localhost:5173, or you can push your new API endpoint to GitHub and deploy it straight to Cloudflare. Then test it by calling the route from curl with:

bash
curl "https://your-website.pages.dev/api/<your-endpoint-name>?min=1&max=100"

for a GET request. Or:

bash
curl -X POST -H "Content-Type: application/json" -d '{"min":1,"max":100}' http://your-website.pages.dev/api/<your-endpoint-name>

for a POST request.

Extra — Why Does the Code Stay on the Backend?

It’s all to do with the Cloudflare adapter we’ve set up in svelte.config.js. The SvelteKit adapter tells it how to compile your Svelte project, following standard rules. The two important ones for us are:

  1. Anything in a +page.svelte file is client-side. It should be compiled into a package and sent to the client when a user visits its route as defined by the directory tree.
  2. Anything in a +server.ts file is server-side. It should be compiled into JS and deployed privately on a Cloudflare worker accessed by an endpoint whose route is defined by the directory tree.

That’s it. We have the file in server.ts, ergo the deployment step shoves it in a backend worker and never sends it to the client.

Final Words

The end! I hope you enjoyed this and it helps you quickly set up and understand backend API endpoints in SvelteKit + Cloudflare. If you want to know more, subscribe! I regularly publish battery-included tutorials on practical Fullstack Engineering.

Catch you in the next one!

Resources

Server-only modules

Routing

Cloudflare