---
title: "SvelteKit health check endpoint | Logdash"
description: "A +server.ts health route for SvelteKit with a database check, a 503 on failure, prerender switched off, and a monitor watching it from outside."
url: https://logdash.io/health-check/sveltekit
---

# SvelteKit health check endpoint

Create src/routes/health/+server.ts, export a GET handler that runs one query and returns json({ ok: true }) or a 503 when the query throws, and set export const prerender = false so the route is built as a real endpoint.

The value of a health route is entirely in what it refuses to say. Returning 200 because the handler ran is worth almost nothing: the Node adapter will happily serve that response from a box whose database credentials expired an hour ago. What you want is a route that goes quiet the moment the app stops being able to do its job, so that the monitor watching it has something real to react to.

One query is enough to get there. Run select 1 through whatever client your load functions use, return json({ ok: true }) when it comes back, and return a 503 when it throws. That status code is the contract with everything downstream - Logdash counts 200 to 399 as up and anything else as down, and alerts on the moment the state changes, so the 503 is what converts a dead connection pool into a message on your phone.

## The endpoint

 src/routes/health/+server.ts 

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

export const prerender = false;

export const GET: RequestHandler = async () => {
  try {
    await db.execute('select 1');
    return json({ ok: true });
  } catch {
    // Second argument is a ResponseInit, same as new Response().
    return json({ ok: false, error: 'db' }, { status: 503 });
  }
};
```

Two things are worth copying from that file beyond the query. The handler imports from $lib/server, which keeps the database client out of any bundle that could reach the browser and makes SvelteKit shout at you if it ever does. And it uses the same client your load functions use, rather than opening a fresh connection, so the check exercises the pool that real traffic depends on. A health route with its own private connection can pass while every page on the site is queued behind an exhausted pool.

## Keep the check small

- One dependency check per thing the app cannot serve without, and no more. Two queries and a Redis ping is a full health check for most apps.
- Do not call your own API routes from it. You end up measuring your own HTTP stack twice and doubling the chance of a false alarm.
- Skip third-party APIs entirely. Their downtime is real, it is just not something an alert to you can fix at 3am.
- Stay under a second. Logdash abandons a request after 10 seconds and records it as down, which is correct behaviour but a confusing way to learn your query is slow.
- Return json({ ok: true }) and stop. Build hashes and adapter details in a public response body help attackers more than they help you.

## Monitor it

1. **Add the endpoint** Add a monitor in Logdash and enter https://yourapp.com/health. The first check fires on save, which is when a typo in the route path is cheap to find.
2. **Pick the check interval** Free is every 5 minutes across five monitors, Builder is every minute, Pro is every 15 seconds. The response time from each check lands on a chart next to the uptime history.
3. **Trigger a real failure** Point DATABASE\_URL somewhere that does not exist and restart the app. The endpoint answers 503, the monitor turns red, and the Telegram alert arrives with the URL and status code in the message.

## Prerendering will lie to you

If prerender is switched on globally in src/routes/+layout.ts, or you are on adapter-static, SvelteKit will try to render this endpoint at build time and bake the response into a file. The build machine has no database, so you either get a build error or, worse, a permanently cached 200 sitting on a CDN answering every check for the next six months. Setting prerender = false in the file itself makes the route dynamic whatever the layout says, and it is one line you will not have to remember when you swap adapters. Worth knowing where the endpoint actually runs, too: on adapter-node it runs in your process and a database check means something, while on a serverless adapter each check may hit a cold function, which is a real number but not the one you thought you were measuring.

### Where do I put a health check route in SvelteKit? 

src/routes/health/+server.ts, which serves GET /health. Any path works, so if the app already owns /health for something else, src/routes/api/health/+server.ts is the usual second choice.

### Should I use json() or new Response() in +server.ts? 

json() from @sveltejs/kit, since it sets the content type and takes a ResponseInit as its second argument, which is where the 503 goes. new Response("ok") is fine if the body is a plain string and you set the status yourself.

### Why does my SvelteKit health check need prerender = false? 

Because a prerendered endpoint is a static file. It runs once on a build machine with no database, then serves that same answer to every monitor forever, which is the exact failure mode a health check exists to prevent.

### What status code should the SvelteKit health route return? 

200 when the query succeeds, 503 when it does not. Logdash marks a monitor down on any status outside 200 to 399, so a correct 503 is the difference between an alert and a green dashboard during an outage.

## Keep reading

[All health check guides](https://logdash.io/health-check): One page per framework, each with the endpoint code and the monitor that watches it.

[Nuxt health check endpoint](https://logdash.io/health-check/nuxt): Add server/api/health.get.ts with a defineEventHandler that runs one query, returns a small object on success, and calls setResponseStatus(event, 503) before returning when the query throws.

[NestJS health check endpoint with Terminus](https://logdash.io/health-check/nestjs): Install @nestjs/terminus, inject HealthCheckService and TypeOrmHealthIndicator into a /health controller, and the endpoint returns 200 while every indicator is up and 503 the moment one goes down.

[FastAPI health check endpoint](https://logdash.io/health-check/fastapi): Add an async /health route that runs SELECT 1 through the session with a short timeout and returns a JSONResponse with status\_code=503 when the query fails, so a live Uvicorn process with a dead database reads as down.

[Uptime monitoring](https://logdash.io/features/monitoring): HTTP checks as often as every 15 seconds. When one fails, Telegram tells you before your users do.
