Quick start
Agents today: MCP or CLI. Humans: Drop or CLI. Same result:
https://{slug}.aft.page.
index.html → a live URL in seconds. No account.
CLI
curl -fsSL https://aft.page/install | sh then aft deploy — no login to ship.
MCP
Point any agent at https://mcp.aft.page/mcp; ask "Deploy this to aft.page".
Claim & share
Keep the URL, invite teammates by email, make it private, rename, roll back.
Secrets / env
Per-site vault after claim. Try URLs are sqlite only.
Custom domains
CNAME to cname.aft.page and get HTTPS on your own hostname.
Capabilities
Declare what an app needs (secrets, egress); an owner approves it on deploy.
Plugin / Skill
npx plugins add vaibhavmule/aft.page — MCP, Skills, Plugins, Unix.
API (one-shot)
curl -X POST https://api.aft.page/v1/deploy \
-H 'Content-Type: text/html' \
-H 'X-Aft-Client: curl' \
--data '<h1>Hello from aft.page</h1>'
Multi-file: JSON { "files": [{ "path", "content" }] }
or multipart. Optional ?slug=vite-hello. A
collision gets a numeric suffix — an existing slug is never
overwritten by a new, unrelated deploy. Full schemas:
/mcp.md.
What we support
aft.page does not run npm run build.
You (or your agent) detect the project, build locally if needed,
then upload ready files.
| Kind | Ship | Live |
|---|---|---|
| Plain HTML | One file via Drop / MCP deploy |
hello.aft.page |
| Multi-file static | HTML + CSS + JS | share-checklist |
| Vite / React / Vue / Svelte / Astro | dist/ only |
vite-hello.aft.page |
| Next.js static export | out/ only |
— |
| Next SSR / Worker | Next.js (SSR) + upstream |
next-hello.aft.page |
Never upload src/, node_modules, or
.next/. Always include index.html for
static sites. Per-framework build steps, verified vs. untested
frameworks, and what still needs a runtime we don't run yet:
Frameworks guide.
Logs
Owner and editors: project page → Logs, or
GET /v1/sites/{slug}/logs. Request-level hits and
errors for the live site, plus recent deploy failures. No IP
addresses. Kept 7 days.
{
"slug": "my-app",
"views": { "today": 12, "d7": 340 },
"lastServedAt": "2026-08-12T09:14:02.000Z",
"events": [
{ "createdAt": "2026-08-12T09:14:02.000Z", "method": "GET",
"path": "/api/widgets", "status": 500, "bytes": 214, "country": "US" }
],
"deployFailures": [],
"observability": {
"window": "12h",
"totals": { "ok": 40, "fourxx": 2, "fivexx": 1, "bytes": 12000, "requests": 43 },
"buckets": [],
"countries": [{ "country": "US", "n": 30 }, { "country": "IN", "n": 13 }]
}
}
events is capped at the most recent 100 rows; only
document-shaped hits and non-2xx responses stick around — noisy
favicon/robots-style paths are filtered before they're stored.
Source
Owner, editors, and viewers: project page →
Source, or
GET /v1/sites/{slug}/files. File list for the
current deploy (or an older one via ?deployId=);
click a text file to preview its contents. This is a private
read of what you uploaded — it's not a public URL, and the live
site is unchanged by looking at it.
{
"slug": "my-app",
"deployId": "dep_abc123def456",
"files": [
{ "path": "index.html", "bytes": 1820 },
{ "path": "assets/app.js", "bytes": 44210 }
]
}
Limits
| Static | worker / next | |
|---|---|---|
| Files | 500 | 500 |
| Per file | 25 MB | 25 MB |
| Total | 100 MB | 100 MB |
Claim within 60 minutes or drop again. Claim guide.
Examples
- hello.aft.page — plain HTML
- vite-hello.aft.page — React + Vite
dist/ - next-hello.aft.page — Next via upstream
- share-checklist.aft.page — static multi-file
Source: examples/ in the aft.page repo.