Each source folder builds independently.
pnpm build # all source folders
pnpm build front # specific folderOne Entry Point for the Whole Project
The build writes dist/run.js - a dispatcher over every source folder in the project. Start it and the whole application is up:
node dist/run.js -p 4556It routes incoming requests by path the same way the dev server does: each folder's base and apiBase decide what it owns, longest prefix first. A project with a marketing site at /, an admin app at /admin and an API-only folder at /svc is one process, one port, no reverse proxy needed to glue the folders together.
Each folder is served as what it is. SSR folders render on the server; CSR folders are served as static assets with a fallback to their index.html; API-only folders answer on their apiBase.
You do not configure any of this - it follows from the generators the folder is built with.
dist/run.js is also what kosmo preview runs, so what you check locally is the same entry point production serve.
Other Runtimes
dist/run.js is built on node:http, which Bun and Deno both implement, so the same file runs unchanged on all three:
node dist/run.js -p 4556This is worth stressing because it is easy to assume otherwise: nothing in the dispatcher is tied to a runtime-specific server API.
It is node:http all the way down, and the compatibility layers in Bun and Deno cover it.
Running Folders Separately
dist/run.js is the simple path, not the only one.
Deploy folders separately when they have separate lifecycles - a marketing site on a CDN and an API in a container, an admin app scaled independently of the public one, or a folder that belongs in a different region entirely.
The per-folder servers below are what dist/run.js dispatches to internally, so nothing changes about how a folder behaves when you run it on its own.
Build Output
dist/
├── run.js # dispatcher over every folder
└── front
├── api
│ ├── app.js # app instance
│ └── server.js # ready-to-use API server
├── client
│ ├── assets/ # scripts, styles, images
│ └── index.html
└── ssr
├── app.js # SSR app instance
└── server.js # SSR server bundleThe SSR output is only present when SSR is enabled.
What to Deploy
When running folders separately, what you deploy depends on how the folder renders. (With dist/run.js this is all handled for you - the section below matters when you split folders across hosts.)
SSR folders - deploy the SSR server only.
The build bundles the folder's backend into the SSR server: one process serves the client assets, renders pages, and answers API requests.
During server-side rendering, the isomorphic fetch client calls your route handlers in-process - no network hop, no localhost round-trip.
After hydration, the same server answers the browser's API calls over HTTP through a built-in gateway that routes everything under the folder's apiBase to the bundled backend.
node dist/front/ssr/server.js -p 4556 # pages + API, one processThere is nothing else to run - dist/front/api/server.js exists in the build output, but deploying it alongside the SSR server would just duplicate the API.
CSR folders - deploy the API server, serve the client statically.
The browser is the only consumer of your API here, and it reaches it over the network: run dist/front/api/server.js and put dist/front/client/ behind any static host or CDN.
API-only folders (no frontend)
Deploy the API server, same as CSR minus the static assets.
Running the API server
For CSR and API-only setups, the simplest deployment is running the bundled server directly:
node dist/front/api/server.js -p 4556For more control, use the app factory at dist/*/api/app.js.
Hono / H3 - app.fetch is a Web Fetch API handler, so it plugs into each runtime's native server directly:
import { createServer } from "node:http";
import { getRequestListener } from "@hono/node-server";
import app from "./dist/front/api/app.js";
createServer(getRequestListener(app.fetch)).listen(3000);Koa - app.callback() is a Node.js (IncomingMessage, ServerResponse) handler. Deno and Bun support it via their node:http compat layer, not via their native serve APIs:
import { createServer } from "node:http";
import app from "./dist/front/api/app.js";
createServer(app.callback()).listen(3000);Or use app.listen() directly for Node only support:
import app from "./dist/front/api/app.js";
app.listen(3000);