Docs
Deploy an app
From code on your machine to an address that answers: import, detection, the check, the build — and the machine-readable result your coding agent reads back.
Agent tools
ingestdetectsetFrameworkdeploystatuslistDeploymentsrollback
One delivery, end to end
The dashboard and your coding agent drive the same work: check the code, build it, and publish only a build that passed a health check.
Import
A folder or ZIP upload, a GitHub import, or
ingestfrom your agent; an update replaces the same project's source and keeps its settings.Detect
Deterministic — no model call, no network — returning a preset (the list below) or
unknown, for you to confirm.Check
Fail-closed rules over the exact snapshot about to be uploaded: a committed provider key (a Supabase
service_roleJWT), a credential form posting off-origin, or seed-phrase collection.Build and publish
The snapshot goes to the provider. A
READYbuild must then answer an anonymous HTTP request before the address moves, and a failure leaves the previous version serving.
What detection returns
Detection reads the app’s root — no model call, no network — and answers with one of these presets, or unknown for you to choose.
- Web
- Next.js
nextjsViteviteAstroastroSvelteKitsveltekitNuxtnuxtjsRemixremixGatsbygatsbyStatic HTMLstatic - Python server
- FastAPI
fastapiFlaskflaskDjangodjangoPythonpython - Go server
- Go
go - JavaScript server
- Express
expressHonohonoNestJSnestjsNode.js servernode - Container
- Dockerfile (container)
container
static skips the build only for a genuinely prebuilt site: an upload that declares a build step is refused with the preset choices rather than published unbuilt. A JavaScript server preset builds one entrypoint file the provider finds by name (app, index or server at the app root or under src/; server alone for the plain Node.js server preset, and the src/main.ts bootstrap for NestJS), and a Python or Go preset builds from the app's own manifest. A container app ships its own container file at its root, which the provider builds into an image.
The result your agent reads
deploy waits, bounded (about twenty seconds), for a settled answer; status continues from there. The answer is machine-readable:
{
"status": "ready",
"managedUrl": "https://franks-kitchen-3f9a1c07b2e4.trytofu.app/",
"serving": true,
"publiclyReachable": true,
"verification": {
"access": "public",
"httpStatus": 200
}
}publiclyReachable is true only when an anonymous request was served — the answer to “can a visitor open it now?”| Result field | What it tells you |
|---|---|
publiclyReachable | true only when an anonymous request was served. |
verification.access | public (served), protection (refused anonymously: access protection, not a failed build) or unreachable (retried once). |
serving | Whether this deployment answers the app's address; ready with serving: false was not published. |
The address to report is managedUrl; a row with no verdict carries a note, never a failed deployment, and an agent must not open that address in a browser to confirm a build. Detection and the check are rules; the build and network are the provider's.
Automatic updates from GitHub
A project imported from a GitHub branch can follow it. With automatic updates on — a paid capability, switched on in the dashboard's Code Source — a push to that branch is deployed through the same check and build as an upload.
- One branch and one app root per project; branch imports only, with no tags or pull-request previews.
- Tofu deploys the latest head of the branch it observes, not every commit.
- A manual upload, a manual GitHub import, an applied repair or a changed preset pauses updates instead of being silently overwritten; turning them on again starts from the next push.
- Tofu stores no GitHub token: each run uses a short-lived token for that one repository with read access only, and checks your access to it again before downloading and before submitting.
- Your agent reads where a project stands with
githubStatusand can turn updates off withgithubSyncDisable; importing and turning them on use your own GitHub session in the dashboard.
History, logs and rollback
History and logs. The dashboard, listDeployments, getBuildLogs and getRuntimeLogs read the hosting provider's own records for the app. Lines that look like credentials are masked — a conservative filter, so an app should still never print its secrets.
Rollback. rollback, the dashboard's Restore, moves the app's address back to an earlier deployment the provider still reports healthy. It builds nothing new, and a target that is no longer healthy is refused with the reason.
Repair. When a build fails, built-in repair diagnoses it and proposes a bounded fix for you to review and apply; nothing reaches your code until you apply it. repairContext hands your agent the same read-only brief.
Quotas
Quotas are enforced before the work. Free is one prebuilt static site — a root index.html, up to 10 MB and 500 files — with 20 uploads and 20 deployments a day; a paid plan publishes up to 5 apps with 50 uploads and 50 deployments a day.
A platform-wide daily bucket sits behind both, shared by every account: a request refused by it is refused by that shared limit, not by your own plan. hostingStatus reads the allowances actually enforced for your account, before a paid call is refused rather than after.
Limits
What a deploy does not do
Nothing resident. A background worker, a scheduler of the app's own or a non-HTTP service has no path here, and an app's own
vercel.jsoncronsentry does not register. The whole boundary, and the way forward, is in Limits.No guessing a monorepo. Tofu does not pick a workspace subdirectory for you: upload the app’s own root.
No preview deployments. Automatic updates follow one branch; a pull request gets no deployment of its own.
Container runtime logs. A container app’s runtime logs have not been readable so far; the read says it is unavailable rather than showing an empty log.
The ship-it layer for vibe-coded apps. Your agent wrote it — Tofu ships it.
Works in all coding agents
© 2026 Tofu
trytofu.ai