Guides
Self-host a project
Run a Robodev project outside hosted Starbase: one process from @robodev-ai/runtime/server that serves its APIs, Robodev Auth, storage, and frontend on your own Postgres, in Docker or on any Node or Bun host.
@robodev-ai/runtime/server runs one project the way hosted Starbase and robodev dev do: the same compile, loadModules, route matching, validation, Robodev Auth, hooks/auth.ts, and schema push, because they are the same runtime. You bring Postgres, a JWT secret, the public URL, and where storage bytes and email go. The project code (database.ts, api/**, hooks/**) does not change, and robodev dev stays the local loop.
The server
- buildProject({ backendDir, buildDir }) compiles at image build time; loadProjectBuild loads it at boot (read-only filesystem is fine). Without a build and with backendDir set, createProjectServer compiles first.
- Schema: database.ts is pushed on boot under a Postgres advisory lock, so replicas apply it once. A change that would lose data throws instead of applying; pass schema: { allowDestructive: true } once, after a backup. schema: { mode: "off" } plus a release step that calls syncProjectSchema does the same out of band. Any table in public that database.ts does not define counts as a drop: give the project its own database.
- Storage: robodev_storage metadata plus a BlobStore for the bytes — { dir } for a volume, or createS3BlobStore (peer dependency @aws-sdk/client-s3; credentials from the AWS default chain). Object URLs stay on your server (/storage/objects/<key>, private ones signed), so the bucket stays private and needs no CORS.
- Email: createSmtpEmailClient (peer dependency nodemailer) for SES, Postmark, and any SMTP provider; the console otherwise. ctx.email templates are not supported.
- Auth emails: magic-link, reset, and email-change codes are mailed with the same link and default wording hosted Starbase uses (<appUrl>?type=…&code=…). resolveAuthEmail(slug, vars) returns your own subject and text, for example a link to your /reset-password page.
- Static: static: { dir } serves a built SPA with the history fallback; /api/** stays the API. Without it, every path goes to the file routes, as on robodev dev.
- GET /healthz checks the database, for load balancer health checks. Every response carries X-Request-Id; with logRequests (default on) each request logs one JSON line.
What it leaves out
- No dev dashboard, DB browser, or MCP endpoint, and no reflected CORS: corsOrigins is an allowlist, empty by default.
- Google and Apple sign-in go through the Starbase identity broker, so they answer 404 (disabledAuthProviders). Password, magic link, and forgot password work.
- ctx.llm, ctx.agent, ctx.pdf, and ctx.push are hosted services and throw *_not_configured. Jobs and sockets are not started; pass your own through clients.
- The /api/user/auth/* rate limit (authRateLimitPerMinute, default 30 per IP and route) is per process.
Pin @robodev-ai/runtime and @robodev-ai/sdk to the versions your robodev CLI uses (robodev 0.66.0: runtime 0.21.0, sdk 0.20.0), so robodev dev and the server run the same runtime.