Skip to main content

Prerequisites

We do not support Windows as development environment. It might work, or it might not.
Unkey installs most tools and dependencies automatically. The only required preinstalled dependencies are:
  • docker
  • git
All other tools are managed via mise, which you’ll install in the next step.

Configure Depot

Unkey uses Depot as the build runner for local development. To get your Depot token, sign in to Depot, then create a token. Name it something like <your-name>-local. The Depot org settings page is only accessible to Depot org owners. If you are not an owner, Depot might redirect you away from the settings page or block access. Ask Andreas for the appropriate token or access path. During bootstrap, paste that token when prompted or manually add it to ./dev/.env.depot.

Bootstrap

Clone the repository and install mise and other tools.
1

Clone the repository

git clone https://github.com/unkeyed/unkey
cd unkey
2

Install and set up mise

You can set up mise manually or use the install script. It pins mise to a specific version and SHA.
./dev/install-mise
3

Bootstrap local configuration

Run the bootstrap task to install the pinned toolchain, create local environment files, write your Depot credentials, and configure the GitHub app. Use the token from Configure Depot when prompted.
mise run bootstrap
If GitHub rate limits mise install, provide a GH_TOKEN when you rerun the task:
GH_TOKEN=$(gh auth token) mise run bootstrap
If you only want to develop on the dashboard, run mise run dashboard. Otherwise continue for a full dev setup.

Run dev mode

Start the full development setup:
mise run dev
You get:
  • Tilt UI at http://localhost:10350
  • Various services port-forwarded
  • Dashboard at http://localhost:3000

Local HTTPS with Frontline (optional)

Set up local TLS for *.unkey.local:
  1. Configure local DNS:
./dev/setup-wildcard-dns.sh
  1. Start the minikube tunnel in another terminal:
mise run tunnel
  1. Open the local domain:
open https://app.unkey.local
Tilt generates trusted TLS certificates using mkcert and Frontline terminates TLS on port 443.

Stop the development environment

mise run down

Environment configuration

Local authentication

Set local auth mode in your .env file:
AUTH_PROVIDER="local"

Optional services

WorkOS authentication:
AUTH_PROVIDER="workos"
WORKOS_CLIENT_ID=<your client ID>
WORKOS_API_KEY=<your API key>
WORKOS_COOKIE_PASSWORD=<your base64 password>
Stripe billing: The dashboard subscription flow needs all four variables in web/apps/dashboard/.env. If any is missing the dashboard treats Stripe as unconfigured and billing calls fail. The product ID lists come pre-filled in .env.example (the shared sandbox catalog), so you only add two values:
  • STRIPE_SECRET_KEY - a test-mode key (sk_test_...) from the shared sandbox.
  • STRIPE_WEBHOOK_SECRET - from forwarding events to your local dashboard:
stripe listen --forward-to http://localhost:3000/api/webhooks/stripe
To set up a fresh Stripe sandbox (products, meters, prices), follow the catalog guide in the infra repo: Stripe Billing. The Deploy billing push (the control-plane worker) is separate and needs only a secret key in dev/.env.stripe. See Deploy Billing Push.

Feature flags

You don’t need Vercel Flags setup to run dashboard code that imports @/lib/flags. When FLAGS is missing, the dashboard uses the noop adapter and resolves each flag to its declared defaultValue. If you’re adding flags, testing remote targeting rules, or using Vercel Toolbar overrides, ask Andreas for the dev values of FLAGS and FLAGS_SECRET. Add them to web/apps/dashboard/.env. They’re stable, so you set them once and forget. See Feature flags for the rest of the workflow.

Seed local data

mise run unkey -- dev seed local

Test locally

Run Go tests with Bazel:
mise run test
Run a single Go test:
mise exec -- bazel test //pkg/cache:cache_test --test_filter=TestCacheName
Run TypeScript tests with pnpm:
mise exec -- pnpm --dir=web test

Code quality

mise run fmt
mise run build

Troubleshooting

Failure: resource_exhausted: too many requests

If you receive an error message similar to the example below, authenticate your terminal with buf. You can sign up for a free account at buf.build.
Failure: resource_exhausted: too many requestssh

Please see https://buf.build/docs/bsr/rate-limits/ for details about BSR rate limiting.
svc/sentinel/proto/generate.go:4: running "go": exit status 1
Failure: resource_exhausted: too many requests

Please see https://buf.build/docs/bsr/rate-limits/ for details about BSR rate limiting.
svc/vault/proto/generate.go:3: running "go": exit status 1
mise run generate: command failed