CodePlans / Self-host

Run it yourself

One Docker image for Railway, Fly.io or your own host — SQLite on a volume or Postgres, picked from DATABASE_URL.

Railway, Fly.io or any Docker host

One image for either database. Migrations run when it starts, and you create the first account in the browser. There's no shell step.

SQLite — the default
choose
Leave DATABASE_URL unset and mount a volume at /data.
good for
One team, the cheapest setup. Runs as a single instance and backs up with volume snapshots.
volume
Required: the database lives on the volume, not in the image, so it survives every deploy. Without one, CodePlans won't start on Railway, Fly.io or Render.
Postgres
choose
Set DATABASE_URL=postgres://…. Railway: ${{Postgres.DATABASE_URL}}.
good for
Managed backups, several instances, zero-downtime deploys. Set AUTH_SECRET.
# Fly.io — SQLite on a volume (fly.toml is in the repo)
fly launch --copy-config --no-deploy && fly deploy
fly logs # copy the setup code, then open /setup

# Any Docker host
docker build -t codeplans .
docker run -p 3000:3000 -v codeplans-data:/data codeplans

Claim the instance in the browser

A fresh instance logs [setup] … enter the setup code: XXXX-XXXX-XXXX, and every page redirects to /setup. Enter the code to create the owner account and workspace. After that /setup is closed.

Only someone who can read the server log can claim it: the code comes from AUTH_SECRET. To skip the step, set ADMIN_EMAIL and ADMIN_PASSWORD.

Step-by-step guides for Railway, Fly.io, Render and Docker →

The setup page: setup code, name, email, password and workspace name

Run it locally in minutes

Local SQLite mode requires no cloud account, no API keys, nothing external.

# Clone and install
git clone https://github.com/SylonZero/CodePlans.git && cd CodePlans
pnpm install

# Configure (defaults work for local SQLite)
cp .env.example .env.local

# Run migrations and create the admin account
pnpm db:migrate
pnpm db:seed

# Start the dev server
pnpm dev

Open localhost:3000 and sign in with admin@example.com / Password1!. Change your password in Settings → Security after first login.

Want realistic demo data? Run pnpm db:seed-demo after the initial seed to populate products, assets, plans, specs, reviews and responsibilities — the data behind every screenshot on this site. All demo accounts use password Password1!.
Running from source on a server? Prefer the Docker image above. For pnpm build && pnpm start, set AUTH_URL to the public URL (Railway, Fly.io and Render domains are detected). If running the dev server on a remote machine, also set ALLOWED_DEV_ORIGINS=your.server.ip.

Accounts & environment variables

An instance is one workspace with its own email and password accounts. REGISTRATION decides how people get in.

REGISTRATION — who can create accounts
invite
The default. Admins invite people from the Team page; /signup says the workspace is invite-only.
open
Anyone who can reach the server can sign up and joins the workspace as an editor.
closed
No sign-up page. Accounts come only from invites, /setup or ADMIN_EMAIL.
Variable Default Description
PORT 3000 Port the server binds to. Railway sets it for you.
REGISTRATION invite invite, open or closed — who can create accounts (see above).
DATABASE_URL SQLite in DATA_DIR postgres://… selects Postgres; file:…, libsql://… or :memory: select SQLite. Unset: $DATA_DIR/codeplans.db.
DB_PROVIDER from the URL sqlite or postgres; only needed to override the URL-based choice.
DATA_DIR /data (image) Where the default SQLite file lives (data outside Docker).
DB_SSL from the URL and host Postgres TLS is off for private hosts (*.railway.internal, *.flycast, localhost) and on otherwise. sslmode= or true/false overrides.
AUTH_SECRET generated (SQLite) Session signing and token encryption key, min 32 chars: openssl rand -base64 32. Required for Postgres
AUTH_URL detected Public URL of the server. Detected on Railway, Fly.io and Render; set it for custom domains and other hosts. Not needed for localhost dev.
ADMIN_EMAIL / ADMIN_PASSWORD — Create the owner account on first boot instead of using /setup. Ignored once any account exists.
ALLOW_EPHEMERAL_DB — On Railway, Fly.io and Render, SQLite won't start unless its folder is on a volume, because each deploy would otherwise wipe it. true allows it for a throwaway trial.
MIGRATE_ON_BOOT on in production Apply pending migrations at server start (behind a Postgres advisory lock). false to run pnpm db:migrate yourself.
ALLOWED_DEV_ORIGINS — Comma-separated hosts allowed to access Next.js dev resources. Needed when running the dev server on a remote machine.
RESEND_API_KEY — Resend API key for transactional email and the fallback notification channel. Without this, verification URLs are logged to the server console — fine for local dev.
RESEND_FROM_EMAIL CodePlans <noreply@codeplans.ai> From address used in outgoing emails. Workspace admins can also set email and Slack up in Settings.
RESEND_API_URLhttps://api.resend.comSend notification email through a Resend-compatible relay.
NOTIFY_WEBHOOK_ALLOWED_HOSTS—Extra hosts allowed for the notification webhook (only hooks.slack.com by default).
CRON_SECRET—Enables /api/cron/notifications (email/Slack retries) for an external cron.
NOTIFY_INTERVAL_SECONDS60Team mode retries notifications in-process at this interval; 0 turns it off.
ANTHROPIC_API_KEY — Enables AI drafting (release notes, design notes). Without it, all AI features are hidden — the app never requires it.
AI_ENABLED true Set false to force AI drafting off even when an API key is configured.
AI_MODEL claude-opus-5 Claude model used for drafting.

See .env.example for the full annotated configuration file.

Built on proven, modern tooling

No heavy abstractions. Readable Next.js App Router code with a clean DB layer you can fork and adapt.

Layer Technology Notes
Framework Next.js 16 App Router Server Components, Server Actions, streaming
Language TypeScript 5.7 Strict mode throughout
Styling Tailwind CSS v4 + Radix UI shadcn/ui component patterns
ORM Drizzle ORM Dual SQLite + Postgres schemas with migrations
Database SQLite local / PostgreSQL cloud Switched via DB_PROVIDER env var
Auth Email & password (bcrypt + Auth.js) Accounts live in the app's own database
Charts Recharts Velocity, effort accuracy, tech debt trends
Documents TipTap + React Markdown Shared typography, GFM tables, task lists, and line breaks in pages and panels
Testing Vitest 483 tests covering data, authorization, reviews, notifications, MCP access, imports and Markdown; isolated temporary SQLite databases plus an opt-in real PostgreSQL migration and behavior verifier