Run it locally

Three ways, in increasing order of how much they resemble a deployment.

cp .env.example .env          # once; compose has no credentials of its own
docker compose up postgres    # the database, for either of the next two
bun dev                       # both apps under the Workers runtime
bun run dev:server            # both apps as plain processes
docker compose up --build     # both apps as containers, plus the database

bun dev runs two wrangler dev sessions, on ports 1337 and 3000. They find each other through wrangler's local registry, so the API reaches the issuer over the same service binding it uses in production rather than over the network — which is the point of running it this way. Neither needs a Cloudflare account: the Hyperdrive binding falls back to localConnectionString, which is the compose database.

Settings that exist only locally live in apps/auth/.dev.vars rather than in vars. wrangler dev reads that file and wrangler deploy cannot upload it, which is the guarantee wanted for the one setting in it — the one that prints sign-in codes to the log.

docker compose here is Docker's plugin or podman-compose; both read the file unchanged.

Migrations are never run for you, in any of the three:

bun run db:migrate            # against DATABASE_URL