Deploy to Production - ElysiaJS | ElysiaJS

ID: 2115https://elysiajs.com/patterns/deploy.html
Source

Deploy to Production

This page is a guide on how to deploy Elysia to production.

Cluster mode

Elysia is a single‑threaded by default. To take advantage of a multi‑core CPU, we can run Elysia in cluster mode.

Create a src/index.ts that imports the main server from src/server.ts and forks a worker for each CPU core:

// src/index.ts
import cluster from 'node:cluster';
import os from 'node:os';
import process from 'node:process';

if (cluster.isPrimary) {
    for (let i = 0; i < os.availableParallelism(); i++)
        cluster.fork();
} else {
    await import('./server');
    console.log(`Worker ${process.pid} started`);
}
// src/server.ts
import { Elysia } from 'elysia';

new Elysia()
    .get('/', () => 'Hello World!')
    .listen(3000);

Elysia on Bun uses SO_REUSEPORT by default, which allows multiple instances to listen on the same port. This only works on Linux.

Compile to binary

We recommend running a build command before deploying to production as it can reduce memory usage and file size significantly. Compile Elysia into a single binary with:

bun build \
    --compile \
    --minify-whitespace \
    --minify-syntax \
    --target bun \
    --outfile server \
    src/index.ts

This will generate a portable binary server that you can run without needing Bun installed on the target machine.

Target

You can specify a target platform:

bun build \
    --compile \
    --minify-whitespace \
    --minify-syntax \
    --target bun-linux-x64 \
    --outfile server \
    src/index.ts
TargetOperating SystemArchitectureModernBaselineLibc
bun-linux-x64Linuxx64glibc
bun-linux-arm64Linuxarm64N/Aglibc
bun-windows-x64Windowsx64
bun-windows-arm64Windowsarm64
bun-darwin-x64macOSx64
bun-darwin-arm64macOSarm64N/A
bun-linux-x64-muslLinuxx64musl
bun-linux-arm64-muslLinuxarm64N/Amusl

Why not --minify

Bun’s --minify flag also reduces function names to a single character, which hampers OpenTelemetry tracing. If you’re not using OpenTelemetry, you may use --minify instead:

bun build \
    --compile \
    --minify \
    --outfile server \
    src/index.ts

Permission

Some Linux distributions may refuse to execute the binary if it lacks executable permissions. Grant them with:

chmod +x ./server
./server

Unknown random Chinese error

If you see an error with random Chinese characters when running the binary, the machine likely lacks AVX2 support. Bun requires AVX2; there is no workaround.

Compile to JavaScript

If you cannot compile to a binary or are deploying to a Windows server, bundle your server to a JavaScript file instead:

bun build \
    --minify-whitespace \
    --minify-syntax \
    --outfile ./dist/index.js \
    src/index.ts

Run it in production mode:

NODE_ENV=production bun ./dist/index.js

Docker

We recommend compiling to a binary for Docker to reduce the image size. Example Distroless Dockerfile:

# Build stage
FROM oven/bun AS build
WORKDIR /app

# Cache packages
COPY package.json package.json
COPY bun.lock bun.lock

RUN bun install

COPY ./src ./src

ENV NODE_ENV=production
RUN bun build \
    --compile \
    --minify-whitespace \
    --minify-syntax \
    --outfile server \
    src/index.ts

# Final stage
FROM gcr.io/distroless/base
WORKDIR /app
COPY --from=build /app/server server
ENV NODE_ENV=production
CMD ["./server"]
EXPOSE 3000

OpenTelemetry

When using OpenTelemetry, it monkey‑patches node_modules/<library>. Exclude the instrumented library from bundling:

bun build \
    --compile \
    --external pg \
    --outfile server \
    src/index.ts

Keep the node_modules directory on the production server and install only production dependencies:

bun install --production

Example package.json:

{
  "dependencies": {
    "pg": "^8.15.6"
  },
  "devDependencies": {
    "@elysiajs/opentelemetry": "^1.2.0",
    "@opentelemetry/instrumentation-pg": "^0.52.0",
    "@types/pg": "^8.11.14",
    "elysia": "^1.2.25"
  }
}

Monorepo

For a Turborepo‑style monorepo, place a Dockerfile under the application folder (e.g. apps/server/Dockerfile). Example structure:

apps
├─ server
│  └─ Dockerfile
packages
└─ config

Docker command:

docker build -t elysia-mono .

Dockerfile:

FROM oven/bun:1 AS build
WORKDIR /app

# Cache packages
COPY package.json package.json
COPY bun.lock bun.lock

COPY /apps/server/package.json ./apps/server/package.json
COPY /packages/config/package.json ./packages/config/package.json

RUN bun install

RUN bun build \
    --compile \
    --minify-whitespace \
    --minify-syntax \
    --outfile server \
    src/index.ts

# Final stage
FROM gcr.io/distroless/base
WORKDIR /app
COPY --from=build /app/server server
ENV NODE_ENV=production
CMD ["./server"]
EXPOSE 3000