Local Development
Prerequisites
Section titled “Prerequisites”- mise — provisions and pins the toolchain
(Node
26.5.0, Bun1.3.14, Caddy2, Railway CLI5) and runs the dev tasks. Bun is still the package manager and runtime; mise just pins it. - A
GITHUB_TOKENwithread:packages— required to install the private@huddlesurety/apiSDK (see below). - Railway access —
mise run envpulls env vars from Railway. - A running API (locally or a deployed environment) for the app to talk to.
-
Install the toolchain + dependencies:
Terminal window mise install # provisions Node/Bun/Caddy/Railway; run `mise run deps` for bun installInstalls authenticate the
@huddlesuretyscope against GitHub Packages viabunfig.toml, which reads yourGITHUB_TOKEN:[install.scopes]"@huddlesurety" = { token = "$GITHUB_TOKEN", url = "https://npm.pkg.github.com" } -
Pull environment variables:
Terminal window mise run env # railway variables … --json > .env.json (env from ENVIRONMENT, default "development") -
Run the dev server:
Terminal window mise run run # bun run dev → next dev --turbopack (auto-runs deps + env first)Optionally, front it with the HTTP/2 dev proxy so the browser speaks h2 to the app (see tRPC over relative origins):
Terminal window mise run proxy # caddy reverse-proxy --from localhost:3001 --to localhost:3000
Run with mise run <task> (mise.toml):
| Task | Command | Notes |
|---|---|---|
run |
bun run dev (next dev --turbopack) |
Local dev server (deps + env first) |
proxy |
caddy reverse-proxy --from :3001 --to :3000 |
HTTP/2 dev proxy in front of Next |
check |
fmt + lint + tsc |
The full pre-push check |
tsc / tsc:watch |
bunx tsc --noEmit |
Typecheck with the native TS7 compiler |
lint |
bunx eslint |
Runs through the TS6 alias (see below) |
fmt |
bunx prettier --write . |
Format |
env |
railway variables … --json > .env.json |
Pull env from Railway |
deps |
bun install |
Install dependencies |
log / clean |
railway logs / rm -rf .env.json .next |
The remaining package.json scripts are just dev, build (next build, which
also typechecks via useTypeScriptCli), and start (next start).
Environment
Section titled “Environment”Pulled from Railway into .env.json (gitignored); .env.local holds dev
overrides, and ENVIRONMENT (default development) selects the Railway
environment. Key variables:
- Server:
API_URL(Go backend base URL —http://localhost:8080locally),JWT_SECRET(HS256 verify),GITHUB_TOKEN(install-time),PORT(the SSR self-call port, default 3000),OTEL_EXPORTER_OTLP_ENDPOINT. - Public:
NEXT_PUBLIC_URL,NEXT_PUBLIC_BRAND_URL,NEXT_PUBLIC_SERVICE_NAME,NEXT_PUBLIC_DEPLOYMENT_ENVIRONMENT,NEXT_PUBLIC_FARO_ENDPOINT.
The tRPC client URL is now decoupled from the serving origin (#135-era
change): in the browser it’s the relative "/api/trpc" (same-origin under any
host, including the h2 proxy on :3001), and during SSR it self-calls
http://localhost:${PORT ?? 3000}/api/trpc. NEXT_PUBLIC_URL is no longer
used for tRPC — it now only builds invite links. next.config.ts lists
allowedDevOrigins: ["localhost:3001"] so the proxy origin can load HMR/assets.
The SDK fetcher still targets API_URL.
Toolchain quirks
Section titled “Toolchain quirks”A couple of non-obvious things about the build setup — both are intentional:
- TypeScript 7 (
tsgo) for typecheck/build, TypeScript 6 for ESLint. TS7’s native binary ships no JS compiler API, whichtypescript-eslintneeds. So the repo installs a second, aliasedtypescript-lint(TS6) andeslint.config.mjsmonkey-patches module resolution so only ESLint uses it.next buildtypechecks viaexperimental.useTypeScriptCli(TS7 ships nolib/typescript.js, so Next must invoke the project-local compiler). - Cache Components + React Compiler are on (
next.config.ts). See Architecture › Cache Components for the prerender-safety patterns this requires.