Skip to main content
API referenceLocal Development

Local Development

This page has been cleared and is ready for updated Builder Studio documentation.

This page describes running Builder Studio locally for development. It covers prerequisites, the one-command dev stack, what that stack wires up for you, and how to verify everything is reachable. For the public HTTP surface that the running app exposes, see the API overview and REST API pages.

One repo, two runtimes
Builder Studio runs as a Next.js App Router app on top of a Convex backend. Local development means running both: Next on a local port and the Convex dev deployment, with a tunnel between them so Convex callbacks and local OAuth/MCP discovery can reach your machine.

Prerequisites

  • Node.js 22.22.2 (matching .nvmrc).
  • Bun 1.3.14 — Builder Studio uses Bun only; do not use npm, pnpm, or yarn.
  • cloudflared for the full local Next.js + Convex + OAuth/MCP callback loop. Install it with brew install cloudflared. (ngrok also works but requires an auth token.)
  • Working local access to the repo's Convex and Vercel accounts when you touch deployments or environment variables.

Install and run

Install dependencies and start the full local stack with two commands:

Install and startbash
# install dependenciesbun ci # start the full local stackbun run dev

bun run dev drives scripts/worktree-dev.sh, which:

  • starts Next.js on port 3008;
  • creates a Cloudflare quick tunnel;
  • syncs INTERNAL_SITE_URL and the MCP_OAUTH_AUTHORIZATION_SERVERS compatibility fallback into both .env.local and Convex;
  • then starts bunx convex dev.
Why the tunnel exists
Convex calls back into Next.js (for workflow runtime dispatch at /api/execute/worker and the /api/reachability health probe), and local OAuth/MCP discovery cannot reach localhost directly. The tunnel bridges that gap. Quick-tunnel URLs are ephemeral and rotate whenever cloudflared restarts, so a stale URL in .env.local or Convex is a common cause of broken callbacks.

Useful variants

  • Inspect resolved config without starting servers: bash scripts/worktree-dev.sh --print-config. Use this to confirm the active port and tunnel URL after a restart.
  • Next-only (no Convex callbacks): bash scripts/worktree-dev.sh --next-only, or run the dev server directly with bun --bun next dev -p 3008 --turbopack. Use this for isolated UI work that does not need workflow execution or OAuth.
  • Regenerate Next route/app types without a full build: bun run typegen.

Manual control

If you need to run the pieces yourself instead of through bun run dev, start them in this order:

  1. Start Next.js

    Run the dev server on port 3008 with Turbopack.

  2. Open a tunnel

    Start a Cloudflare quick tunnel pointed at http://localhost:3008 so Convex and OAuth/MCP discovery can reach your local Next server.

  3. Sync the tunnel URL

    Set INTERNAL_SITE_URL to the tunnel URL in both .env.local and Convex. Strict MCP discovery advertises the Convex issuer from NEXT_PUBLIC_CONVEX_SITE_URL or NEXT_PUBLIC_CONVEX_URL; MCP_OAUTH_AUTHORIZATION_SERVERS is only a fallback issuer list.

  4. Start Convex

    Run bunx convex dev. Only one worktree may run Convex against the same deployment at a time.

Manual stackbash
# 1. Next.js dev serverbun --bun next dev -p 3008 --turbopack # 2. Cloudflare quick tunnel (Convex/OAuth/MCP callbacks)cloudflared tunnel --url http://localhost:3008 # 3. point the local stack at the tunnel (both places)bunx convex env set INTERNAL_SITE_URL "<tunnel-url>"#    and set INTERNAL_SITE_URL in .env.local to the same value # 4. Convex dev backendbunx convex dev
One Convex deployment, one runner
Only one worktree or process may run convex dev against the same deployment at a time. If callbacks start failing, the usual causes are a rotated or dead tunnel, a stale URL in .env.local or Convex, or another worktree already running Convex against the same deployment.

Verify the stack is reachable

Confirm the Convex-to-Next callback path is healthy with the runtime reachability probe. It should return { "ok": true }:

Reachability probebash
bunx convex run --typecheck disable --codegen disable \  devTools:checkRuntimeRouteReachability \  '{"routeLabel":"/api/execute/worker","probePath":"/api/reachability"}'# -> { "ok": true }

Browser and manual workflow starts enter through /api/execute/start; the public POST /api/execute entry point is retired. OAuth and MCP discovery use the public app URL for /api/mcp and the Convex HTTP actions issuer for authorization-server discovery.

Environment and Convex CLI

.env.local holds your Convex deployment binding (for example CONVEX_DEPLOYMENT) and a deploy key so bunx convex runs non-interactively. Common Convex CLI commands:

CommandWhat it does
bunx convex devRun the local Convex dev backend and watch for changes.
bunx convex codegenRegenerate convex/_generated/. Do not hand-edit generated files.
bunx convex env set KEY "value"Set a Convex environment variable on the dev deployment.
bunx convex env listList Convex environment variables. This prints live values — treat the output as sensitive.
bunx convex run <module>:<fn> '<json>'Invoke a Convex function with JSON arguments.
Never print or commit secrets
bunx convex env list prints live secret values, not just names. Do not paste that output into docs, issues, chat, or commits, and do not commit raw environment dumps or credentials.

Verify your changes

Before pushing substantive changes, run the repo gate. The authoritative check is bun run check (typecheck plus validation); run bun test for application changes.

Verificationbash
bun run typecheckbun run typecheck:convexbun run lintbun testbun run check   # typecheck + validate, the authoritative gate
Build typechecking
next.config.ts keeps typescript.ignoreBuildErrors = false by default, so a production-style build enforces app TypeScript. The dedicated deploy build sets NEXT_DISABLE_BUILD_TYPECHECK=1to skip Next's duplicate pass, but only after the build pipeline has already run bun run check.

Related

Was this page helpful?