/ docs / self-host

Run your own CRRT.

CRRT is OSS-first. crrt.ai is the easy path, but the same code runs on your own infra in under twenty minutes if you'd rather own the stack.

Hosted vs self-host

PropTypeRequiredDescription
crrt.aimanagedoptionalSign up, create a project, paste the snippet. We run the API, the DB, and the agent bridge.
self-hostOSSoptionalYou run the API + dashboard + DB. Full control, no third-party data hop, paid tier features come built-in.
The OSS and hosted versions are the same code on the same trunk. You can switch from hosted to self-host (or back) by changing apiBase on the widget.

What you'll need

  • Postgres for the data layer. Any provider works; we recommend Supabase so you get auth + storage in the same place — that's what the hosted instance runs on.
  • A runtime that can serve the Vercel-style serverless functions in api/ plus the static builds in apps/landing/ and apps/dashboard/. We deploy to Vercel; Fly, Render, Cloudflare Workers, or a Node container all work.
  • Bun ≥ 1.1 for the build commands (bun install, bun run build).

1. Clone and install

bash
git clone https://github.com/thedesignproject/CRRT.git
cd CRRT
bun install

2. Configure environment

Copy .env.example to .env and fill in the required values. The dashboard includes the public SUPABASE_KEY in its browser bundle at build time. Keep SUPABASE_SERVICE_ROLE_KEY server-only.

bash
cp .env.example .env

# Supabase (API + dashboard build):
SUPABASE_URL=https://<your-project>.supabase.co
SUPABASE_KEY=<anon-or-publishable-key>
SUPABASE_SERVICE_ROLE_KEY=<service-role-key> # server-only; never expose in client code
REVIEWER_API_TOKEN=<long-random-string>
SHARE_TOKEN_SECRET=<long-random-string>

# client (landing build-time):
VITE_API_BASE=https://<your-app-url>/api
SUPABASE_SERVICE_ROLE_KEY, REVIEWER_API_TOKEN, and SHARE_TOKEN_SECRET are sensitive — rotate them periodically and never commit or expose them to client code. The two application tokens should be long random strings (32+ bytes).

3. Apply the schema

The Drizzle schema lives in db/schema.ts; migrations are committed under db/migrations/. Run them once before your first deploy.

bash
bun run db:migrate

deploy-build runs db:migrate automatically on each deploy, so subsequent schema bumps apply themselves.

4. Deploy

On Vercel

bash
vercel deploy        # preview
vercel --prod        # production

vercel.json sets buildCommand to bun run deploy-build, which typechecks, builds the landing app and dashboard into one output, and applies pending migrations.

On another runtime

The relevant outputs are:

  • apps/landing/dist/ — static landing page.
  • apps/landing/dist/dashboard/ — static dashboard SPA (build with bun run build:dashboard).
  • api/ — Vercel-style serverless handlers using @vercel/node. Adapt them to your platform if needed.

5. Smoke test

bash
curl -s "$APP_URL/api/v1/public/comments?projectKey=demo-project"
# → [] on a fresh DB, or seeded comments if you ran `bun db:seed`

You should get a JSON response. If you ran bun db:seed, a demo-project row already exists for testing the widget end-to-end.

Updates and versioning

crrt.ai runs whatever is on trunk. If you self-host, you can pin to a release tag (git checkout v0.x.y) for stability. We aim to keep the public API surface backward-compatible across minor versions. The Drizzle migrations are idempotent, so re-running bun run db:migrate after a fetch is safe.

Going further

Custom branding — replace the assets in apps/landing/public/ and tweak branding/crrt/tokens.css if you want to white-label.

Custom auth — the dashboard uses Supabase Auth out of the box. Swap apps/dashboard/lib/supabase.ts and api/_lib/auth.ts if you need a different provider.

Issues, questions, contributions — open them on the GitHub repo. We track every one.