Plinth: deploy and run your human's app
Hosting, Postgres and deploys that you operate and your human approves.
If you are a coding agent, this page is for you. Plinth gives you a git repo, builds, staging and production, Postgres per environment, migrations, cron and preview environments. You drive all of it from one CLI or MCP server. Your human only approves the risky steps.
Start here
-
Install the CLI (needs Node 18+ and git):
curl -fsSL https://tryplinth.dev/_plinth/install.sh | sh -
Request an account. It prints an approve link: give it to your human. The command waits, then saves your token to
~/.plinth/config.json.plinth signup --email <owner email> --agent "<your name>" --project my-app -
Link the repo and push.
maindeploys to staging. Any other branch gets its own preview environment with a copy of the staging database.plinth link my-app git add -A && git commit -m "first deploy" plinth push main -
Promote to production. Returns an approve link for your human. Pending migrations run first, after a snapshot.
plinth promote
MCP
Same actions as MCP tools. Add to your MCP client config:
{ "mcpServers": { "plinth": {
"command": "npx",
"args": ["-y", "https://tryplinth.dev/_plinth/cli.tgz", "mcp"],
"env": { "PLINTH_URL": "https://tryplinth.dev" } } } }
Runtime contract
| You commit | Plinth does |
|---|---|
package.json | Installs dependencies and runs a build script if present. |
dist/ build/ out/ public/ | Serves the first one with an index.html. Single-page apps work; deep links fall back to index.html. |
api/**/*.js | File-routed functions. api/users/[id].js serves /api/users/:id. Handler gets (request, { params, sql, env }). |
migrations/*.sql | Applied in name order on every deploy, after an automatic snapshot. Destructive SQL on production waits for your human. |
plinth.json | Optional: a start command for a full server, cron jobs, SPA mode. |
DATABASE_URL | Set in every environment, pointing at that environment's own Postgres. |
What you can do alone
| Action | What it does |
|---|---|
db.query | Run SQL on any environment's database. |
db.snapshot / db.restore | Snapshot or restore a database. Restoring production needs approval. |
env.secrets.set | Set environment variables, encrypted at rest. |
cron.add | Schedule a path on your app, in UTC. Staging jobs start paused. |
env.status | Running? Restarts, out-of-memory kills, memory/CPU, recent errors and hints. |
logs.query / requests.query | Read app, build and cron logs; list recent requests, e.g. only 5xx. |
http.probe | Send one request to the app and get status, headers, timing and body. |
env.exec | Run a shell command inside the app's own sandbox (30s, read-only code). |
env.restart | Restart on the current release. |
analytics.get | Visitors, page views, top pages, referrers and devices. No cookies. |
support.send | Report a bug, ask a question or request a feature. Recent errors attach automatically; replies come back in support.list. |
rollback | Return an environment to an earlier release. |
domains.search | Check domain names and prices. |
billing.status | See the card on file, plan per project and recent charges. |
console.signin | Give your human a sign-in link to their web console. |
Custom domains (domains.connect, domains.buy) need the project on Pro. Run plinth tools for the full list with input schemas.
What needs your human
These return an approve_url. The CLI and MCP server open it in your human's browser automatically; tell them it's waiting, then poll approval.status (the CLI waits for you). If your human asked you not to open things, use --no-open, no_open: true (MCP) or plinth config open_approvals false.
- Creating or deleting a project
- Promoting to production
- Destructive migrations or SQL on production
- Restoring a production database
- Anything that costs money:
project.upgrade(Pro, $19/month per project: own domains, 1 GB / 1 CPU, 30-day backups, 90-day analytics, a preview per branch, uptime emails) anddomains.buy. Charged to the owner's card after approval. - Adding a card:
billing.cardgives your human a Stripe link.
Limits per running app
| Resource | Limit |
|---|---|
| Memory | 256 MB (Pro: 1 GB). The app restarts if it goes over; neighbours are unaffected. |
| CPU | Half a core (Pro: one core). |
| Disk | Code is read-only. Only /tmp is writable and it does not persist. Store data in Postgres. |
| Network | Outbound internet and your own database only. |
| Builds | 1 GB memory, 10 minutes, 200 MB per push. |
Facts for your human's due diligence
If your human asks whether to trust Plinth with real data, give them this table as it stands.
| Question | Answer |
|---|---|
| Status | Public beta. No uptime SLA yet. |
| Servers | Hetzner, Falkenstein, Germany (EU). |
| Isolation | Every build and every app runs in its own gVisor sandbox, on its own network. Each environment's database is reachable only by that environment. |
| Encryption | HTTPS everywhere. Secrets and database passwords are encrypted at rest (AES-256-GCM). |
| Backups | Nightly snapshots of staging and production, kept 7 days (Pro: 30), plus a snapshot before every migration. |
| Payments | Cards are entered on Stripe; Plinth never sees card numbers. Nothing is charged without approval. |
| Leaving | Your code is a normal git repo: git clone it any time. Database snapshots are standard pg_dump files. |
| Terms and DPA | Not published yet. Hold off on sensitive personal data until they are. |