Publishing & Custom Domains¶
You can ship a Doable project to the public web with one click.
Publish¶
In the editor toolbar, click Publish.
What happens:
- The API runs the project's production build (
vite build). - The output is copied to
SITES_DIR/<project-slug>/. - The reverse proxy (Caddy or nginx) starts serving the site at
<slug>.<DOABLE_DOMAIN>. - The project's row gets a
published_attimestamp.
You'll see a green Live badge with the URL; click to open in a new tab.
Re-publish¶
Each click of Publish rebuilds and redeploys. Old versions aren't kept by default; for that, see Version History.
Unpublish¶
Project → Settings → Publishing → Unpublish. The site stops being served (returns 404) and published_at is cleared.
The default URL¶
Your project lives at:
DOABLE_DOMAIN is set by the operator (typically doable.me or a self-hosted equivalent). The slug is derived from the project name and editable in Project → Settings → URL slug.
Custom domains¶
Want myapp.com instead?
- Project → Settings → Domain → Add custom domain.
- Enter your domain.
- Doable shows the DNS record you need to set on your DNS provider:
- For most setups: a
CNAMEpointing to<DOABLE_DOMAIN>. - For Cloudflare-Tunnel-based deployments: a
CNAMEto<CLOUDFLARE_TUNNEL_ID>.cfargotunnel.com(orange cloud). - Add the record at your registrar / Cloudflare.
- Click Verify. Doable checks DNS, issues an SSL cert (Let's Encrypt or via Cloudflare), and starts serving the site at the custom domain.
The status will move through pending_dns → pending_verification → active. If it gets stuck:
- Wait; DNS propagation can take up to 48h.
- Click Re-verify.
- Check Project → Settings → Domain → Diagnostics for the exact error.
Multiple domains¶
A project can have multiple custom domains (e.g. myapp.com and www.myapp.com). Add them one at a time.
The free plan limit on custom domains is set by the operator (packages/shared/src/constants.ts).
Apex domains¶
Most DNS providers don't allow CNAME at the apex (example.com vs www.example.com). Use one of:
- ALIAS / ANAME / CNAME-flattening records (Cloudflare, DNSimple, Route 53 Alias).
- An
Arecord to your server's static IP.
SSL¶
You don't manage certs yourself. Caddy (or nginx + certbot) does it on demand. Renewals happen automatically.
Sites' env vars¶
Your project can have published-time env vars under Project → Settings → Environment variables. These are baked into the static build (VITE_* prefixed for Vite to expose them to the client).
For server-side env vars (API routes), Doable's published projects are static-only today; you'd need to deploy a separate backend.
Security & isolation¶
Each published project is served from its own subdirectory in SITES_DIR. The reverse proxy enforces the URL → directory mapping; users can't traverse out of their site root.
The build runs inside the same dovault jail as the dev server, so a malicious or buggy build script can't affect other users' files.
See also¶
- Custom Domains deployment guide for operators wiring up the DNS / Caddy side.
- API Keys & Auto-Provisioning for how published apps securely call MCP tools and integrations.
MCP Tools & Integrations in Published Apps¶
If your project uses MCP tools (e.g. connected databases, HPCA, Supabase) or integrations (Slack, Stripe, etc.), they continue to work after publishing, automatically.
What happens on publish¶
- Doable scans your source for
doable.mcp.call(...)anddoable.integrations.run(...)patterns - A scoped API key is created, only authorized for the tools your app uses
- The key is baked into your production bundle at build time
- Your published site calls the Doable API proxy directly (cross-origin, secured by the key)
No configuration needed¶
The @doable/sdk detects whether it's running in:
- Preview (in the editor) → uses a short-lived JWT token
- Published site → reads the auto-provisioned API key from the build
Same code, zero changes between environments.
Adding or changing MCP tools after first publish¶
If you add a new MCP connector, remove one, or the AI generates code using different tools:
- The AI generates code using the new MCP tools
- Click Publish again: this is required
- The auto-provisioner re-scans your code, detects new/changed tools, and updates the key's scope
- The published site now has access to the updated tools
Always re-publish after changing MCP connectors
The API key scope is determined at build time by scanning your source code. If you add a new MCP to your workspace and the AI writes code using it, that code won't work on the live site until you re-publish.
You do NOT need to re-publish when the MCP server's underlying data changes (e.g. new database records), only when the set of tools your app calls changes.
See API Keys & Auto-Provisioning for the full list of what triggers a re-publish.
Security¶
Published apps never see raw MCP server credentials. The connector proxy:
- Decrypts credentials server-side
- Validates the API key's tool scope and origin
- Rate-limits requests
- Logs every call for audit
See API Keys & Auto-Provisioning for the full security model.