Skip to content
Sidecars in development

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:

  1. re-imports the entry
  2. calls teardown() on the running service
  3. calls the close function that service's start() returned
  4. 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:

src/mailer/kosmo.config.ts
ts
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:

kosmo.config.ts
ts
defineConfig({
  // ...
  sidecar: { entry: "./entry.mjs" },
  typecheck: false,
});

Released under the MIT License.