Start
Offline dev with robodev dev
Run a created project's schema, APIs, jobs, sockets, and storage on your machine — embedded Postgres, file routes, Swagger, and Robodev Auth — with no Starbase account or hosted project.
robodev dev serves the project you already have on disk. It starts a real Postgres, compiles database.ts plus api/**, jobs/**, hooks/**, and sockets/** with the same esbuild path hosted deploy uses, pushes the schema, and listens on http://localhost:4000. Jobs enqueue and cron onto reserved robodev_jobs tables in that Postgres. Sockets serve on ws://localhost:4000/sockets/…. Storage bytes live under .robodev/dev/storage with metadata in reserved robodev_storage tables. No robodev auth, no project id, and no Starbase account. Google sign-in is the one network hop to Starbase: a project-less identity broker talks to Google and returns a short-lived assertion. Password, magic link, and forgot-password stay offline.
Run it
- Run it from the project root, from robodev/, or from apps/fe — it walks up looking for database.ts, robodev/database.ts, or packages/be/database.ts (Tiny).
- Postgres data lives in .robodev/dev/pg, so rows and Auth users survive restarts. That folder is already gitignored.
- Storage bytes live in .robodev/dev/storage (also gitignored). Metadata is in reserved robodev_storage tables on the same Postgres. --database-url still writes bytes under .robodev/dev/storage.
- The Postgres port is picked free on every start unless you pass --db-port.
- Editing database.ts, api/**, jobs/**, hooks/**, or sockets/** recompiles and reloads in place. A successful reload closes open sockets with 1012 deployed so clients reconnect. A compile error keeps the previous build and its sockets serving.
What it serves
- File routes exactly as hosted: api/planets.ts is GET /api/planets, api/planets/[id].ts is GET /api/planets/:id.
- Jobs: ctx.jobs.enqueue and defineJob({ cron }) run after compile. Queue and cron live in reserved robodev_jobs tables on the local Postgres, not in database.ts. Startup logs each job; a zero-job project prints nothing about jobs.
- Sockets: GET /sockets/<name> from sockets/**/*.ts on ws://localhost:{port}. Startup logs each as WS /sockets/…. A zero-socket project prints nothing about sockets.
- Storage: ctx.storage.upload / get / getUrl / delete / list. Public GET /storage/objects/{key} returns 200 and the bytes (no S3 302). Private objects need a local Auth Bearer or a valid exp+sig.
- Robodev Auth: /api/user/auth/register, login, refresh, magic-link, forgot-password, /api/user/me, and Google start + callback (GET /api/user/auth/google and /api/user/auth/google/callback). Magic-link and reset codes print to the terminal instead of sending mail.
- GET /openapi.json and Swagger at /_robodev/docs (Scalar at /_robodev/scalar). Dashboard at /_robodev (Overview, APIs, Jobs, Emails, Auth, Storage, Sockets; JSON at /_robodev/state.json).
- GET /_robodev/ready for a readiness check.
- PDF: ctx.pdf.fromHtml POSTs HTML to {STARBASE_URL}/internal/pdf. No local Chromium. See PDF (/docs/pdf).
- CORS is open to localhost, so a Vite frontend on :3000 can call it directly.
With the frontend
Space, Auth chat, and Marketplace have a root dev script that runs the API and apps/fe together, with VITE_API_URL pointed at the local API. Backend and Empty have no frontend, so their dev script runs robodev dev alone.
You can also run them separately: robodev dev in one terminal, then cd apps/fe && bun dev in another with VITE_API_URL=http://localhost:4000.
Schema changes
The schema is pushed with drizzle-kit, the same non-migration reconcile hosted deploy runs. Non-destructive changes apply on their own. A destructive plan is printed and skipped until you rerun with --force, so a rename never silently drops a column full of local data.
Flags
- --port <n> — API port (default 4000).
- --db-port <n> — Postgres port (default 0, meaning pick a free one).
- --database-url <url> — use a Postgres you already run instead of the embedded one.
- --force — apply destructive schema changes.
- --no-watch — compile once and serve, without watching files.
- --with-fe — also start apps/fe with the local API pre-wired.
GET /api/user/auth/google?redirect_uri= (or api.auth.signIn.google()) completes Sign in with Google without a Starbase account, hosted project, or your own Google Cloud OAuth client. The local API 302s to {STARBASE_URL}/internal/auth/google/dev. Starbase talks to Google with the platform client; the consent screen is the Robodev app. After Google, Starbase 302s back to http://localhost:<port>/api/user/auth/google/callback with a short-lived identity assertion. Local Auth upserts robodev_auth.users in that project's embedded Postgres and mints tokens with prj-local / robodev-dev-local-secret.
- STARBASE_URL defaults to https://robodev.povio.dev. Override is process env only (STARBASE_URL=http://localhost:4000 to dogfood a local Starbase). The project .env STARBASE_URL is not read for this hop.
- To use your own Google client instead, put both GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in the project-root .env and register http://localhost:<port>/api/user/auth/google/callback on that client. --port changes that URI. One of the two vars set is 503 google_oauth_unconfigured.
- Each robodev dev has its own .robodev/dev/pg. The same Google email can exist in each project independently.
What still needs hosted Starbase
- ctx.llm, ctx.agent, and ctx.push throw llm_not_configured / llm_not_configured / push_not_configured. They are not implemented offline.
- ctx.pdf.fromHtml hops to Starbase (STARBASE_URL, default https://robodev.povio.dev). Process env only — the project .env STARBASE_URL is not read. See PDF (/docs/pdf).
- The Jobs dashboard and dead-job retry stay hosted-only. Offline jobs have no retry UI; a dead row stays dead until you enqueue again.
- Real SMTP. ctx.email prints to the terminal.
- Project secrets: ctx.env comes from a .env file at the project root.
- Custom domains, hosted request logs, and the Starbase dashboard. Local request, email, job, Auth, Storage, and Sockets events are on the dashboard at /_robodev.
Next
Deploy the same tree with robodev deploy (/docs/deploy). Local development (/docs/local) covers the hosted-project workflow. CLI reference (/docs/cli) lists every command.
robodev dev and robodev deploy run the same runtime package, so a route that works locally serves the same way once deployed.