In dev mode, kosmo serve can run a sidecar alongside your app, so a worker is up while you work on the routes that feed it. Whether it does is the serve key.
Without serve, a sidecar is built and left alone - it is a build artifact like any other, and starting it is yours. With serve: true, kosmo serve imports the entry into its own Vite environment and calls start().
When the entry changes - or any file it imports - it:
- re-imports the entry
- calls
teardown()on the running service - calls the close function that service's
start()returned - calls
start()on what it just imported
The import comes first so that a save that cannot compile changes nothing: it throws at step 1, and the service keeps running.
It is one process, so there is no signal to catch and nothing to wait for on exit - but that also means the close function is the only thing that frees a port.
Return one that actually closes the server, or the next reload hits EADDRINUSE and keeps hitting it until you restart the dev server.
A reload that throws is reported, the dev server stays up, and the next good save retries.
Development only
kosmo preview and dist/run.js build sidecars but never start them. Details ›
When not to serve
serve earns its keep when the service holds something open between edits - a socket bound, a consumer subscribed, a pool connected. That is what makes a restart worth doing, and the close function is what releases it.
A sidecar whose start() holds nothing has none of that. There is no socket to rebind, nothing for the reload to free, and no state that being up between saves preserves - the dev server is only re-running a function that returns.
Leave serve off and let it be a build artifact:
export default defineConfig({
sidecar: {
entry: "./entry.ts",
run: "./run.ts",
// nothing to keep alive between edits - build it, start it yourself
serve: false,
},
});An empty close function is the tell. If there is nothing to put in it, there is nothing serve: true is keeping alive for you.
Typechecking
Nothing to configure. A sidecar lives inside a source folder, and a folder's tsconfig.json already covers everything under it, so pnpm typecheck mailer checks it like any other file in the folder.
A sidecar that wraps third-party JavaScript, or one you simply do not want checked, opts out with the folder-level typecheck key:
defineConfig({
// ...
sidecar: { entry: "./entry.mjs" },
typecheck: false,
});