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 git@github.com: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 dev in the CLI reference.

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