Local Development
Setting up local databases and development environment for Bklit Analytics
Local Development
This guide will help you set up a complete local development environment with local databases, so you can develop safely without touching production data.
Quick Start: For first-time setup, use npx @bklit/create instead of manual configuration. This guide is for advanced users who want manual control.
Optional Features: Polar billing, OAuth providers, Resend email, and Mapbox are all optional. Core analytics features work without them. See Environment Variables for details.
Prerequisites
Before you begin, ensure you have:
- Node.js >= 22.0.0
- pnpm >= 9.6.0
- Docker (for ClickHouse)
Overview
Bklit uses two databases:
- PostgreSQL - User data, projects, organizations (via Prisma Dev)
- ClickHouse - Analytics events and session data (via Docker)
In development, you'll use local instances of both databases that are completely isolated from production.
Environment Variables
We use environment variable prefixes to separate local development from production:
DEV_*prefixed variables are automatically used whenNODE_ENV=development- Regular variables (without prefix) are used in production
This design makes it impossible to accidentally connect to production databases during development.
Setting Up Your .env File
The setup wizard creates this automatically, but for manual setup:
# ===================
# REQUIRED - Auto-generated by wizard
# ===================
AUTH_SECRET="auto-generated-32-byte-secret"
DATABASE_URL="postgresql://..."
CLICKHOUSE_HOST="http://localhost:8123"
# ===================
# OPTIONAL - OAuth Providers
# ===================
# AUTH_GITHUB_ID="your-github-id"
# AUTH_GITHUB_SECRET="your-github-secret"
# AUTH_GOOGLE_ID="your-google-id"
# AUTH_GOOGLE_SECRET="your-google-secret"
# ===================
# OPTIONAL - Billing (Polar.sh)
# ===================
# POLAR_SERVER_MODE="sandbox"
# POLAR_ORGANIZATION_ID="your-org-id"
# POLAR_ACCESS_TOKEN="your-token"
# POLAR_WEBHOOK_SECRET="your-secret"
# ===================
# OPTIONAL - Email (Resend)
# ===================
# RESEND_API_KEY="your-resend-key"
# ===================
# OPTIONAL - Maps (Mapbox)
# ===================
# NEXT_PUBLIC_MAPBOX_TOKEN="your-mapbox-token"
# ===================
# OPTIONAL - Background Jobs (Trigger.dev)
# ===================
# TRIGGER_SECRET_KEY="your-trigger-secret"
# TRIGGER_API_KEY="your-trigger-api-key"
# ===================
# Development Only
# ===================
NODE_ENV="development"
NEXT_PUBLIC_APP_URL="http://localhost:3000"In development without optional services:
- π Login OTPs appear in your terminal
- π§ Emails are logged to console
- πΊοΈ Geographic data shows as list view (no map)
- π³ All users have free tier access
Initial Setup
Follow these steps once to set up your local development environment.
1. Install Dependencies
pnpm install2. Start ClickHouse
Start Docker Desktop, then start ClickHouse:
pnpm dev:servicesOr let it start automatically when you run pnpm dev (recommended).
3. Start Prisma Dev
In a separate terminal, start the local Prisma Postgres server:
cd apps/dashboard
npx prisma devWhen the server starts, press h to view the HTTP connection URL. You should see output like:
prisma+postgres://localhost:51213/?api_key=eyJkYXRhYmFzZVVybCI6...Copy this URL and update the DEV_DATABASE_URL in your .env file.
Important: Keep this terminal running! Prisma Dev needs to stay active.
4. Run Database Migrations
With Prisma Dev running, open another terminal and run:
# Migrate Postgres (creates all tables)
pnpm db:migrateYou should see output confirming the connection to localhost:51213:
Datasource "db": PostgreSQL database "postgres" at "localhost:51213"Then migrate ClickHouse:
cd packages/analytics
pnpm run migrate5. Clean and Generate
Clear Next.js cache and regenerate Prisma client:
cd apps/dashboard
rm -rf .next
cd ../..
pnpm db:generate6. Start Development Servers
# Start dashboard and playground (default)
pnpm dev
# Or start everything including website and trigger.dev
pnpm dev:fullYour local environment is now ready! Visit http://localhost:3000 to see the dashboard.
Daily Workflow
Once set up, your daily development workflow is simple:
Terminal 1: Start Prisma Postgres
cd apps/dashboard
npx prisma devKeep this running throughout your development session.
Terminal 2: Start Your App
pnpm devThis automatically starts ClickHouse and runs the dashboard and playground apps.
Verifying Your Setup
To confirm you're connected to local databases and not production:
Check Database Connections
When you start pnpm dev, watch the terminal output. You should NOT see any references to:
accelerate.prisma-data.net- Your production ClickHouse host
Check Your Data
- You should not be automatically logged in
- You'll need to create a new account locally
- No production projects or data should be visible
Use Prisma Studio
Open Prisma Studio to inspect your local database:
cd packages/db
pnpm studioThis opens at http://localhost:5555 and should show your local database with empty tables.
Available Commands
| Command | Description |
|---|---|
pnpm dev | Start dashboard and playground (ClickHouse starts automatically) |
pnpm dev:full | Start all apps including website and trigger.dev |
pnpm dev:services | Manually start ClickHouse only |
pnpm dev:services:stop | Stop ClickHouse |
pnpm db:migrate | Run Postgres migrations on local DB |
pnpm db:studio | Open Prisma Studio (local DB) |
pnpm db:generate | Regenerate Prisma Client |
pnpm dev:docs | Start documentation site |
How It Works
Automatic Environment Switching
The codebase automatically uses DEV_* variables when NODE_ENV=development:
In Application Code:
Before database clients initialize, packages/db/src/client.ts and packages/analytics/src/client.ts override process.env with DEV_* values in development mode. This ensures Prisma and ClickHouse clients always connect to local databases.
// In packages/db/src/client.ts
if (process.env.NODE_ENV === "development" && process.env.DEV_DATABASE_URL) {
process.env.DATABASE_URL = process.env.DEV_DATABASE_URL;
}In CLI Scripts:
Database migration and management commands use a with-env-dev wrapper that substitutes DEV_* variables:
pnpm db:migrateβ UsesDEV_DATABASE_URLpnpm db:studioβ Connects to local databasepnpm run migrate(in analytics package) β UsesDEV_CLICKHOUSE_*variables
This means you can safely run any command without accidentally touching production data.
Running Database Migrations
When updating Bklit or applying schema changes, you may need to run migrations:
PostgreSQL (Prisma) Migrations:
pnpm db:migrateClickHouse Migrations:
For ClickHouse schema updates (like adding new columns), use the migration scripts in apps/dashboard/scripts/:
# Cross-platform (recommended for Windows contributors)
cd apps/dashboard
pnpm tsx scripts/migrate-clickhouse-pageviews.ts
# Unix shell script (macOS/Linux only)
cd apps/dashboard
./scripts/migrate-clickhouse-pageviews.shSee the scripts README for details on specific migrations.
Docker Compose
The docker-compose.yml at the project root defines the ClickHouse service:
- Image:
clickhouse/clickhouse-server:latest - Ports:
8123(HTTP),9000(Native) - Data persistence via Docker volumes
- Health checks to ensure service is ready
Troubleshooting
ClickHouse Won't Start
Error: Cannot connect to the Docker daemon
Solution:
- Open Docker Desktop
- Wait for it to fully start
- Run
pnpm dev:servicesorpnpm dev
Error: Port conflicts or service issues
Solution:
# Stop and remove all data
docker-compose down -v
# Start fresh
pnpm dev:servicesPrisma Postgres Issues
Error: Migrations fail or connection errors
Solution:
# Stop Prisma Dev (Ctrl+C)
# Remove all local instances
npx prisma dev rm '*'
# Start fresh
npx prisma dev
# Update DEV_DATABASE_URL in .env with new connection string
# Run migrations again
pnpm db:migrateError: Migration fails with "relation does not exist" or database state issues
This commonly happens on first-time setup when migrations can't apply cleanly. Since you're starting fresh, you can bypass migrations entirely:
Solution (Fresh Setup Only):
# Navigate to the db package
cd packages/db
# Force reset and push schema directly (skips migration history)
pnpm with-env-dev prisma db push --force-reset --schema=./prisma/schema.prisma
# Generate Prisma client
pnpm generate
# Return to project root
cd ../..This approach:
- Drops all tables and recreates them from your schema
- Bypasses migration history (ideal for fresh local setup)
- Accepts data loss (not a problem for new local environments)
Still Seeing Production Data
If you're seeing production data or accelerate.prisma-data.net in logs:
- Verify
NODE_ENV=developmentis at the top of your.env - Clear all caches:
cd apps/dashboard rm -rf .next rm -rf node_modules/.cache - Regenerate Prisma client:
pnpm db:generate - Restart dev server
Reset Local Databases
Reset Postgres:
cd packages/db
pnpm with-env-dev prisma migrate resetReset ClickHouse:
cd packages/analytics
pnpm run clear-data
pnpm run migrateArchitecture
Applications
- Dashboard - Main SaaS application (Next.js)
- Playground - SDK testing environment (Vite + React)
- Docs - Documentation site (Next.js)
- Website - Marketing site (Next.js)
Local Databases
- Postgres - User data, projects, organizations, sessions (Prisma Dev)
- ClickHouse - Page views, events, analytics sessions (Docker)
Development Flow
- User creates account locally (stored in Postgres)
- Creates projects and organizations (stored in Postgres)
- Integrates SDK in playground or test app
- SDK sends events to local API
- Events stored in ClickHouse
- Dashboard queries ClickHouse and displays analytics
All of this happens entirely on your machine with no connection to production services.
Testing Webhooks Locally
Why Tunnels Are Needed
Polar and Resend webhooks can't reach localhost. Use a tunnel to expose your local server for webhook testing.
Setup with ngrok (Recommended)
1. Install ngrok:
- Visit https://ngrok.com/download
- Follow installation instructions
2. Start services:
# Terminal 1: Prisma Dev
cd apps/dashboard
npx prisma dev
# Terminal 2: Your app
pnpm dev
# Terminal 3: ngrok
ngrok http 30003. Copy ngrok URL:
From ngrok output, copy the HTTPS forwarding URL:
Forwarding https://abc123.ngrok.io -> http://localhost:30004. Configure webhooks:
Polar:
- Dashboard β Settings β Webhooks
- URL:
https://abc123.ngrok.io/api/webhooks/polar - Secret: Your
POLAR_WEBHOOK_SECRET
5. Test:
- Create test subscription in Polar sandbox
- Check Polar webhook logs
- Verify your organization plan updates
Alternative: Cloudflare Tunnel
cloudflared tunnel --url http://localhost:3000Use tunnel URL: https://abc123.trycloudflare.com/api/webhooks/polar
Important Notes
- Free tunnel URLs change on restart - Update webhook URLs accordingly
- Use sandbox mode:
POLAR_SERVER_MODE="sandbox"in.env - Optional for basic dev - Webhooks only needed for testing subscriptions
- Production uses your domain - No tunnels in production
Skip Webhooks
For basic development without webhook testing:
- Keep
POLAR_SERVER_MODE="sandbox" - Webhooks will fail gracefully (expected)
- Manage subscriptions in Polar UI
- Test webhooks in staging/production
Related Documentation
- Architecture Overview - System architecture
- Contributing - Contribution guidelines
- Getting Started - Quick start guide