Kylndocs

Deployment

kyln bake compiles your app into a self-contained dist/ that runs with Bun and nothing else: no src/, no node_modules. Copy dist/ to your server, run it, and you're live.

Build

kyln bake

A scaffolded app also wires a build script that runs any asset step (such as compiling your stylesheet) before kyln bake, so bun run build is the one command for a full production build.

What bake produces

dist/
├── client/                 # static assets, served at /
│   ├── index.html          # each page, prerendered to static HTML
│   ├── <route>/index.html  # one prerendered page per route
│   ├── styles.css          # compiled CSS
│   └── <entry>-<hash>.js   # the client bundle
└── server/
    └── index.js            # the self-contained production server

Two halves: client/ holds static assets and a prerendered HTML page for each route, and server/index.js is a small standalone server that serves them plus your API routes.

Because pages are prerendered, a request for a page returns real HTML on the first byte, so crawlers and first paint get content, not an empty shell that waits for JavaScript.

Run

bun dist/server/index.js

The server listens on PORT when one is set; otherwise it falls back to your config's server.port, which bake bakes into the bundle at build time, and to 2500 when neither is given. It runs from dist/ alone, with no source and no dependencies, serving the prerendered pages, static assets, and any API routes.

Deploy

The whole deploy is: build, copy dist/ to the host, run it.

kyln bake
scp -r dist/ user@host:/srv/my-app/
# on the host:
bun /srv/my-app/dist/server/index.js

Run it behind your process manager and reverse proxy of choice. Nothing else from your project needs to ship.

Containers

The self-contained dist/ makes for a minimal image: copy dist/, run it with Bun.

FROM oven/bun:1.3
WORKDIR /app
COPY dist/ ./dist/
EXPOSE 2500
CMD ["bun", "dist/server/index.js"]

Build your dist/ first (kyln bake), then build the image against it. There's no node_modules layer and no source: the image is essentially Bun plus your dist/. The server honors PORT, so a platform that injects one needs no extra configuration.

Persisting scheduler data

If your app uses scheduled tasks, the scheduler keeps its state in a small SQLite database. By default that database lives under your working directory (.kyln-ai/decisions.db), which on an ephemeral container filesystem is lost on every restart. Point it at a persistent volume with KYLN_DB_PATH:

KYLN_DB_PATH=/data/kyln.db bun dist/server/index.js

Mount /data as a persistent volume and scheduled-task state survives restarts and redeploys. This matters specifically for apps with a src/scheduled/ directory: the standalone server runs the scheduler just as kyln dev and kyln serve do, so a containerized deployment needs the durable path or it silently loses schedule state. An app with no scheduled tasks has no scheduler database and nothing to persist.

Running from the project

kyln bake + the standalone bundle is the self-contained path. There's also kyln serve, which runs a production server from your project directory (using the built assets). Use kyln serve to check a production build locally; use the baked dist/ for a shipped deployment where you want nothing but Bun and your build on the host.

Next

That completes the framework tour: routing, rendering, data, access, scheduling, testing, and shipping. Head back to any guide from the sidebar, or start building.