alepha@docs:~/docs/guides/deployment$
cat 1-bare.md | pretty
2 min read
Last commit:

#Bare Deployment

The default deployment target. alepha build produces a self-contained dist/ folder that runs on any machine with Node.js or Bun installed.

#Build

bash
alepha build

This bundles both server and client code into a single optimized output. The server bundle includes all dependencies -- no npm install is needed in production.

#Run

bash
node dist        # Node.js
bun dist         # Bun

The server starts on http://localhost:3000 by default. Configure the host and port with environment variables:

bash
SERVER_HOST=0.0.0.0 SERVER_PORT=8080 node dist

#Output Structure

bash
dist/
  index.js       # Server entry point
  public/        # Client assets (if React frontend exists)
  drizzle/       # Database migrations (if using $entity)

If no React frontend is present, only index.js is generated.

#Runtime Flag

Optimize the build for a specific runtime:

bash
alepha build --runtime=bun

The --runtime=bun flag uses Bun-specific export conditions during bundling.

#Configuration

Set the target in alepha.config.ts to avoid passing flags:

typescript
1import { defineConfig } from "alepha/cli/config";2 3export default defineConfig({4  build: {5    target: "bare",6    runtime: "node",7  },8});

bare is the default target. You do not need to set it explicitly unless you want to override a different default.

#Deployment

Copy the dist/ folder to any server and run it. No build tools, no package managers, no configuration files required on the target machine.

Works on:

  • VPS (DigitalOcean, Hetzner, Linode)
  • Bare metal servers
  • Any container runtime
  • systemd, PM2, or any process manager

#Multi-replica $job cron jobs

When you run more than one replica (e.g. 10 Docker instances behind a load balancer), $job({ cron, ... }) acquires a per-job distributed lock by default so the handler runs once per tick across the fleet, not once per replica. The default MemoryLockProvider is per-process — to get cross-replica coordination, register a real lock provider:

ts
1import { AlephaLockRedis } from "alepha/lock/redis";2 3const app = Alepha.create()4  .with(AlephaLockRedis)   // Redis-backed lock store5  .with(AlephaApiJobs);

Set lock: false on a $job if you genuinely want every replica to fire the handler.

#Retry granularity

$job retries are sweep-driven on every platform: no exponential backoff. A failing handler is rescheduled with scheduledAt = now and the next sweep tick (default */5 * * * *, configurable via jobConfig.sweepCron) picks it up. Lower sweepCron if you need tighter retry latency.