LAZ
LAZ

Reputation: 534

sveltekit: how do I run startup/init code before anything else

The env:

How do I run startup code, before the server starts handling requests? I need to start multiple services before a single request is handled, and for it to happen when I start the server, not when the first hook runs in hooks.server.js. I tried putting some init functions outside the handle hook but then they run during build because of ESmodules/tree shaking.

Edit: Elaborating a bit, since it isn't very obvious what the implications are. Assuming the goal is to have a DB class you can import and use anywhere in the project, so within a +server.js file for example, you'd import the class and init() it somewhere. If the startup script is meant to init(), then it can't be part of the build process, because the build will run the top level code and try to establish connections. It not being part of the build process means I can't just `import db from 'db'; because the output of the build generates dozens of chunk files which won't be in the correct locations, or have the same name as before.

hooks.server.js

import db from 'db';
import redis from 'redis';
import wss from 'websocket';

const runAllTheInitFunctions = async () => {
    await db.init();
    ...
}

await runAllTheInitFunctions(); // Can't go here, so... where?

/** @type {import('@sveltejs/kit').Handle} */
export const handle = async ({ event, resolve }) => {
    ...
}

I must be missing something obvious, so hopefully someone has found an elegant solution aside from checking init on every handle(). Thank you in advance.

Upvotes: 1

Views: 3085

Answers (3)

davidhigh
davidhigh

Reputation: 15518

As of 2025, the canonical way is to use the init function. Straight from the Sveltekit docs:

import * as db from '$lib/server/database';
import type { ServerInit } from '@sveltejs/kit';

export const init: ServerInit = async () => {
    await db.connect();
};

This function runs once, when the server is created or the app starts in the browser, and is a useful place to do asynchronous work such as initializing a database connection.

Upvotes: 0

LAZ
LAZ

Reputation: 534

Somehow missed this in the docs after reading them over multiple times. Found a reference to it in a git issue.

https://kit.svelte.dev/docs/building-your-app#during-the-build

The answer is I run the code exactly like before, at the top of my hooks.server.js file, but adding a check to see if it's running within a build:

import db from 'db';
import redis from 'redis';
import wss from 'websocket';
import { building } from '$app/environment'; // <---- here

const runAllTheInitFunctions = async () => {
    await db.init();
    ...
}

if (!building) {                             // <---- here
    await runAllTheInitFunctions();
}

/** @type {import('@sveltejs/kit').Handle} */
export const handle = async ({ event, resolve }) => {
    ...
}

Upvotes: 6

brunnerh
brunnerh

Reputation: 185280

The Node adapter generates a middleware handler, so you could just set up a server script that contains your startup logic and uses the handler.

Abridged example from docs:

import { handler } from './build/handler.js';
import express from 'express';
 
const app = express();
app.use(handler); 
app.listen(3000, () => {
  console.log('listening on port 3000');
});

Upvotes: 0

Related Questions