Skip to content

Development Setup

This guide walks you through getting the main OpenCauldron Next.js application running locally so you can develop and test changes before opening a pull request.

  • Node.js 20+ or Bun 1.0+ (Bun is recommended — all scripts use it)
  • Docker for local Postgres, or a Neon connection string
  • A Google Cloud project with OAuth credentials configured for http://localhost:3000
  • At least one AI provider API key (for testing generation)
  • Git

Fork opencauldron/opencauldron on GitHub, then clone your fork:

Terminal window
git clone https://github.com/YOUR_USERNAME/opencauldron
cd opencauldron

Add the upstream remote so you can pull in future changes:

Terminal window
git remote add upstream https://github.com/opencauldron/opencauldron

Terminal window
bun install

Copy the example env file:

Terminal window
cp .env.example .env.local

Open .env.local and fill in the required values.

Terminal window
# Database — local Docker Postgres (see step 4) or a Neon connection string
DATABASE_URL="postgresql://cauldron:cauldron@localhost:5432/cauldron"
# Auth
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="" # openssl rand -base64 32
# Google OAuth
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""

For Google OAuth, create credentials at console.cloud.google.com/apis/credentials. Set the authorized JavaScript origin to http://localhost:3000 and the redirect URI to http://localhost:3000/api/auth/callback/google.

Add at least one AI provider key in the AI MODELS section so you can test generation. Any key will work:

Terminal window
GEMINI_API_KEY="" # Google AI Studio — free tier available

See the API Keys guide for how to obtain keys for every supported provider.

For local development, use the local filesystem backend — no credentials needed:

Terminal window
STORAGE_PROVIDER="local"

If you are using local Postgres via Docker:

Terminal window
docker compose up db -d

This starts a Postgres 16 container using the credentials in .env.example. The container exposes Postgres on port 5432.

If you are using Neon, skip this step and set DATABASE_URL to your Neon connection string.


Push the schema to your database:

Terminal window
bun run db:push

Use db:push for local development. It applies schema changes directly without generating migration files, which is faster when iterating.


The feats (achievement badges) system requires a seeded badges table. Without it, no badges will be awarded and the feats UI will be empty.

Terminal window
bun tsx src/lib/db/seed-badges.ts

You only need to run this once (and again after upgrades that add new badges).


Terminal window
bun run dev

The app starts at http://localhost:3000. Sign in with Google to create your account.


CommandWhat it does
bun run devStart Next.js dev server with hot reload
bun run buildProduction build — run this before opening a PR
bun run lintRun ESLint across the codebase
bun run db:pushPush schema changes to the local database
bun run db:migrateApply versioned migrations (production workflow)
bun run db:studioOpen Drizzle Studio in the browser

After signing in for the first time, your account is created with the member role. To access admin features (user management, usage dashboards), promote yourself in Drizzle Studio:

Terminal window
bun run db:studio

Open https://local.drizzle.studio, find your row in the users table, and set role to admin.


Before starting new work, sync your fork with upstream:

Terminal window
git fetch upstream
git checkout main
git merge upstream/main

The main app is a standard Next.js App Router project. Key directories:

src/
├── app/ Next.js App Router pages and API routes
│ ├── api/ API endpoints (generate, poll, upload, etc.)
│ └── (app)/ Page routes behind auth
├── components/ React components
├── lib/
│ ├── db/ Drizzle schema, client, and seed scripts
│ └── ... Shared utilities
├── providers/ AI provider implementations + registry
└── types/ Shared TypeScript interfaces and unions

The provider system — where most new integrations live — is in src/providers/. The GenerationProvider interface and all shared types are in src/types/index.ts.


Before pushing a branch, run:

Terminal window
bun run lint
bun run build

Both must pass cleanly. The build step catches type errors that the dev server may not surface.