Deployment
Building and deploying an evjs application requires two parts: serving the static client assets and running the API server for server functions.
Build for Production
npm run build
# Under the hood: npx ev build
This creates:
dist/client/— Static React SPA and assetsdist/server/— Backend server functions bundledist/client/manifest.json— Client asset map and route metadatadist/server/manifest.json— Server function registry
Option 1: Node.js (Default)
The default and simplest deployment option:
// server.mjs
import { serve } from "@evjs/server/node";
import { serveStatic } from "@hono/node-server/serve-static";
import * as serverBundle from "./dist/server/main.js";
// 1. Initialize the Hono app with server functions
const app = serverBundle.createApp();
// 2. Serve the static client bundle
app.use("/*", serveStatic({ root: "./dist/client" }));
app.get("*", serveStatic({ path: "./dist/client/index.html" }));
// 3. Start the server
serve(app, { port: process.env.PORT || 3000 });
Run with: node server.mjs
Option 2: Docker
Multi-stage Dockerfile for production deployment:
# Stage 1: Build
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
COPY server.mjs .
EXPOSE 3000
CMD ["node", "server.mjs"]
Option 3: Deno
Use the ECMA adapter for Deno deployment:
// ev.config.ts
export default defineConfig({
server: {
runtime: "deno run -A", // During dev
},
});
// server.ts
import { serveStatic } from "hono/deno";
import * as serverBundle from "./dist/server/main.js";
const app = serverBundle.createApp();
app.use("/*", serveStatic({ root: "./dist/client" }));
app.get("*", serveStatic({ path: "./dist/client/index.html" }));
Deno.serve({ port: 3000 }, app.fetch);
Run with: deno run --allow-net --allow-read server.ts
Option 4: Bun
Similar to Deno, using Bun's native serve:
// server.ts
import * as serverBundle from "./dist/server/main.js";
const app = serverBundle.createApp();
export default {
port: 3000,
fetch: app.fetch,
};
Run with: bun server.ts
Environment Variables
Server secrets (e.g., DATABASE_URL, API_KEY) are safe — they only evaluate at runtime on the server. Ensure they are injected into your Node/Docker/Edge environment before starting the app.
All server function code runs exclusively on the server. Client bundles only contain RPC stubs — your secrets and business logic are never exposed to the browser.