Production build
Generate client and server bundles, then run Runable without a Vite server.
The production build generates the client and, when SSR is enabled, a server bundle. Runable then uses these files without starting the Vite development server.
runable build runs this same loadConfig() + buildProduction() sequence for you. Write your own build script, as shown below, only when you need to run other steps around it.
Create the build script
// scripts/build.ts
import { buildProduction, loadConfig } from "runable";
await loadConfig();
await buildProduction();Add project commands:
{
"scripts": {
"build": "tsx scripts/build.ts",
"start": "RUNABLE_MODE=production tsx server.ts"
}
}Install tsx as a development dependency when your server and script remain in TypeScript.
Understand the output
With the default distdir, Runable writes to .output/:
.output/
├── client/
│ ├── index.html
│ └── assets/
├── server/ # present when ssr: true
└── manifest.jsmanifest.js connects the Runable server to the client template and compiled SSR entry point.
Start the existing server
Your server.ts does not change:
import Express from "express";
import { express } from "runable/adapters/express";
const server = Express();
server.get("/api/health", (_req, res) => {
res.json({ status: "ok" });
});
server.use(express());
server.listen(Number(process.env.PORT ?? 3000));With RUNABLE_MODE=production, the adapter loads configuration but does not create a Vite server. It serves generated client assets and renders the application from .output. When RUNABLE_MODE is unset, Runable uses development mode.
Prepare deployment
Copy into the production environment:
.output/;- the server and its runtime dependencies;
runable.config.tsor its compiled version;- required environment variables.
Always test the startup command with RUNABLE_MODE=production before deployment.
The production server expects .output/manifest.js. If it is missing, run the build or check distdir.
On this page