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+ and pnpm (the project’s package manager)
  • 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
pnpm 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.


Apply the SQL migrations to your database:

Terminal window
pnpm exec drizzle-kit migrate

This applies all pending migrations in order. Use drizzle-kit migrate — not db:push. The db:push command bypasses migration history and fails on a fresh database that needs the pgvector extension.


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
pnpm exec tsx src/lib/db/seed-badges.ts

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


Terminal window
pnpm run dev

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


CommandWhat it does
pnpm run devStart Next.js dev server with hot reload
pnpm run buildProduction build — run this before opening a PR
pnpm run lintRun ESLint across the codebase
pnpm exec drizzle-kit migrateApply versioned migrations
pnpm exec drizzle-kit generateGenerate a migration after editing the schema
pnpm 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
pnpm 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
pnpm run lint
pnpm run build

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