Skip to content

Development

Run Pug locally from source: dev infrastructure, code generation, tests and the demo seeder.

Updated View as Markdown

Run the whole Pug stack on your machine — backend, backing services, and (optionally) the dashboard — from clone to a working server you can point an SDK at.

Install the prerequisites from Requirements first: Docker, a Go ≥ 1.26 toolchain, and — if you want the dashboard — Bun.

1. Clone and configure

git clone [email protected]:pug-sh/pug.git
cd pug
cp .env.example .env

.env.example is pre-filled with defaults that match the dev Docker Compose (Postgres on 5433, ClickHouse on 9000, NATS on 4222, Dragonfly on 6380). Open .env and set at least:

PUG_JWT_SECRET_KEY=<any-long-random-string>

Full variable reference: Configuration.

2. Start infrastructure

make infra-up      # `make infra` is an alias

This runs docker compose -f infra/dev/docker-compose.yaml up -d, starting the four backing services — each with a health check, a named volume for persistence, and its own bridge network:

Service Image Host port(s) Role
PostgreSQL postgres:18 5433 → 5432 Auth, orgs, projects, config
NATS nats:2.14-alpine 4222 / 6222 / 8222 JetStream (started with --jetstream); monitoring on 8222
ClickHouse clickhouse-server:26.5 8123 / 9000 / 9009 Event storage (nofile raised to 262144)
Dragonfly dragonfly:v1.38.1 6380 → 6379 Redis-compatible cache

The compose file is for local development only — not a production topology. In production you run these as managed services or your own cluster. Stop the containers with make infra-down.

Target Compose action
make infra-up Start the four services detached
make infra-up-fg Start them in the foreground (logs to your terminal)
make infra-down Stop and remove them

3. Run migrations

Run once before the first boot and again after each upgrade. Order doesn’t matter — they’re safe to re-run.

go run ./cmd/pug postgres migrate
go run ./cmd/pug nats migrate
go run ./cmd/pug clickhouse migrate

Each reads its connection details from .env (DATABASE_URL, NATS_URL, CLICKHOUSE_URL). There is no make migrate target — migrations are pug commands. Use go run ./cmd/pug … here, or ./bin/pug … after make build.

4. Seed test data (optional)

Populate the demo project with synthetic events and profiles so there’s something to query right away:

go run ./cmd/pug seed --count 10000

pug seed resets Postgres and ClickHouse, then generates events and seeds profiles for the users behind them. The default is 500,000 events — pass --count to keep it light on a laptop. See the CLI reference for all flags (--batch, --no-reset).

There is a single pug seed command — not per-store postgres seed / clickhouse seed. It handles both stores itself.

5. Start the dev server

go run ./cmd/pug dev      # `pug start` is an alias

pug dev starts the API server and all workers together in one process. On boot it prints the server URL and the active worker list; the server listens on :3000 (override with PUG_SERVER_PORT). Press Ctrl+C to stop everything cleanly. See CLI reference → dev.

Compiled alternative

To run the compiled binary (or reproduce how production binaries are built):

make build
./bin/pug dev

make build compiles bin/pug plus a standalone binary per worker and migration runner — see Deployment → Build.

6. Run the dashboard (optional)

To use the UI locally, clone and run pug-sh/app alongside the backend:

cd ../app        # separate repo
bun install
bun run dev      # http://localhost:5173

Its default VITE_API_BASE_URL is http://localhost:3000, which already matches your local pug dev — no extra config. The backend’s default PUG_CORS_ORIGINS (http://localhost:5173) already allows the Vite dev server, so sign-in works out of the box.

7. Point an SDK at localhost

Set the endpoint to http://localhost:3000 when initializing an SDK:

import { init } from '@pug-sh/browser'

init('YOUR_PROJECT_ID', {
  apiKey: 'pub_YOUR_PUBLIC_KEY',
  endpoint: 'http://localhost:3000',
})

The default endpoint is Pug Cloud, so this override is required to hit your local server. Full per-SDK guidance: Connect your SDKs.

Observability (ClickStack)

By default the backend logs to stdout as text — no collector required. To view traces, metrics, and logs locally, start the optional ClickStack overlay, which adds a HyperDX OTLP collector and UI on top of the dev services:

make clickstack        # infra + HyperDX collector (OTLP :4317/:4318) + UI (:3001)

Then set the OTLP endpoint in .env and restart pug dev:

OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317

Pug auto-detects the endpoint at startup and exports there instead of logging to stdout; open the HyperDX UI at http://localhost:3001. Stop it with make clickstack-down. The overlay is infra/dev/docker-compose.clickstack.yaml, layered onto the base compose file.

Make targets

Everyday

Target What it does
make infra-up / make infra-down Start / stop the dev backing services
make clickstack / make clickstack-down Add / remove the local OTLP collector + HyperDX UI
make build Compile all binaries into bin/
make test Run the Go test suite with the race detector
make cover Run tests and write coverage.out
make lint Lint Go code (golangci-lint)
make psql Open a psql shell in the running Postgres container
make chql Open a clickhouse-client shell in the running ClickHouse container

Code generation (when editing backend source)

Pug generates code from three sources; regenerate after editing the corresponding inputs, then commit the output:

Target Regenerates Run after editing
make sqlc Type-safe Go query code (into internal/gen/repo) SQL query files under schema/postgres
make rpc Connect RPC / protobuf Go (lints protos first) .proto files under proto/
make templ Compiled Go for the transactional email templates templ email templates
make gen-ts TypeScript types from the protos .proto files (for the dashboard/SDKs)

Common issues

Symptom Fix
make infra-up fails Confirm Docker is running; check for port conflicts on 5433, 4222, 8123, 6380
Migrations fail Run make infra-up first and wait for the containers to report healthy
pug dev exits immediately Check .env exists and DATABASE_URL / NATS_URL / CLICKHOUSE_URL are reachable
Events not arriving Confirm the events worker started (it’s listed in the pug dev output)
SDK requests fail with a network error Set the SDK endpoint to http://localhost:3000 explicitly — the default is Pug Cloud, not your local server
Dashboard can’t sign in Ensure the backend is running and its PUG_CORS_ORIGINS includes http://localhost:5173

Further reading

Navigation

Type to search…

↑↓ navigate↵ selectEsc close