Turn a local artifact folder into a temporary public URL.
npx vanish-cli site ./demo --root index.html
# https://quiet-river-42.vanish.sh/Vanish is built for agent and terminal workflows: Codex writes a mini-site, Claude Code produces an HTML report, a script exports Markdown/CSS/JS, and you need a real URL to send to someone without deploying an app.
Single-file uploads still work for screenshots, PDFs, decks, and quick handoffs.
Publish a static folder:
npx vanish-cli site ./demo --root index.htmlThe root file is what Vanish serves at /. Vanish does not transform files: HTML is HTML, Markdown is served as Markdown, and CSS/JS/assets are served as static files.
Install the CLI when you use it regularly:
npm install -g vanish-cli
vanish site ./demo --root index.htmlUpload one file:
npx vanish-cli upload screenshot.png
# https://vanish.sh/f/a1b2c3d4e5f6.pngVanish is meant to be a distribution channel for generated artifacts, not a long-lived hosting platform.
Recommended routing for coding agents:
- Use
vanish-publish-sitewhen the artifact is a folder, browser demo, static report, or mini-site. - Use
vanish-upload-fileswhen the artifact is a single file, screenshot, deck, PDF, spreadsheet, archive, or generated document. - Use
vanish-connect-upgradefor login, quota, retention, custom slugs, and API key issues.
The skills include a privacy gate. They should ask before publishing suspected secrets, credentials, customer data, private documents, source maps, or unreleased proprietary material.
Publish a folder:
vanish site ./demo --root index.html
# https://quiet-river-42.vanish.sh/Publish Markdown as the root:
vanish site ./notes --root README.md
# https://silver-meadow-k9.vanish.sh/Update an existing owned site:
vanish site ./demo --root index.html --update quiet-river-42
# keeps the same public URL and replaces the filesUse a paid-plan slug:
vanish site ./demo --root index.html --slug workshop-demo
# https://workshop-demo.vanish.sh/Custom retention:
vanish site ./demo --root index.html --days 90
# Pro, up to 365 daysJSON output:
vanish site ./demo --root index.html --jsonReturns non-breaking fields such as:
{
"url": "https://quiet-river-42.vanish.sh/",
"id": "k8m2q9z4p1ad",
"rootPath": "index.html",
"size": 8120,
"fileCount": 3,
"expires": "2026-05-12T10:30:00.000Z",
"expiresInHours": 48,
"tier": "free",
"updateCommand": "vanish site ./demo --root index.html --update k8m2q9z4p1ad"
}Agent-safe preflight:
vanish site ./demo --root index.html --dry-run --json --no-clipboardStable owner-scoped channels create the first URL, then update it on later runs:
vanish site ./demo --root index.html --channel pr-42 --verify --json --no-clipboardProtect an authenticated site with a shared password:
printf '%s' "$CLIENT_PREVIEW_PASSWORD" |
vanish sites access pr-42 --mode password --password-stdin
# Restore normal link access
vanish sites access pr-42 --mode linkPro accounts can reserve one permanent Vanish namespace, then publish up to 20 site routes below it:
vanish domains reserve studio
vanish site ./portfolio \
--root index.html \
--channel portfolio \
--domain portfolio.studio.vanish.shDNS is managed by Vanish for these routes. Each child hostname gets its own TLS certificate, while the namespace remains reserved independently of site expiration.
Pro accounts can also attach one custom subdomain to a stable channel:
vanish domains add studio.example.com --channel homepage
# Add the CNAME/TXT records printed by the command
vanish domains verify studio.example.comThe custom domain can act as a namespace too. Add a direct child for another site and point the printed CNAME/TXT records at Vanish:
vanish site ./portfolio \
--root index.html \
--channel portfolio \
--domain portfolio.studio.example.com \
--verifyEvery hostname follows its channel across updates. Domain lifecycle commands:
vanish domains ls
vanish domains attach portfolio.studio.example.com --channel another-preview
vanish domains rm portfolio.studio.example.com
vanish domains releaseCustom domains support subdomains. Apex domains such as example.com are
intentionally rejected. A parent domain or Vanish namespace cannot be removed
until all of its child routes have been removed.
Lifecycle commands:
vanish sites ls --json
vanish sites info quiet-river-42 --json
vanish sites verify quiet-river-42 --json
printf '%s' "$PREVIEW_PASSWORD" | vanish sites verify quiet-river-42 --password-stdin --json
vanish sites extend quiet-river-42 --days 90 --json
vanish sites rm quiet-river-42 --jsonvanish upload screenshot.png
# https://vanish.sh/f/a1b2c3d4e5f6.png
vanish upload report.pdf --days 90
# ProOutput formats:
vanish upload image.png --md
vanish upload data.json --json
vanish upload file.png --no-clipboard
vanish upload file.png --idempotency-key retry-safe-123 --json --no-clipboardAuthenticated file uploads can be deleted from the CLI:
vanish rm a1b2c3d4e5f6Share several related files behind one public URL:
vanish bundle report.pdf screenshot.png logs.txt --json --no-clipboardvanish login # GitHub OAuth, saves API key
vanish whoami # show username and tier
vanish status # show storage usage and limits
vanish ls # list file uploads
vanish rm <id> # delete a file upload
vanish sites ls # list mini-sites
vanish keys ls # list API keys
vanish keys create --name agent-ci
vanish keys revoke <prefix>
vanish upgrade # Pro: 10 GB for 10 EUR/month
vanish update # update the CLI to the latest version| Anonymous | Free | Pro | |
|---|---|---|---|
| Account needed | No | GitHub login | GitHub login |
| Mini-sites | Static folders | Static folders | Static folders |
| Site URL | Readable random | Readable random | Random or custom slug |
| Domain identity | No | No | 1 vanish.sh namespace + 1 custom subdomain |
| Site domain routes | No | No | Up to 20 below owned namespaces |
| Password protection | No | Yes | Yes |
| Site limits | 10 MB, 100 files | 500 files, within 50 MB total | 5,000 files, within 10 GB total |
| File uploads | Images only | All except executables | All except executables |
| Max file size | 5 MB | 50 MB | 1 GB |
| Total storage | Ephemeral only | 50 MB | 10 GB |
| Retention | 24 hours | 48 hours | 30 days, up to 365 |
| Rate limit | 10/hour | 50/hour | 500/hour |
| Price | Free | Free | 10 EUR/month |
Config is read in this order:
- CLI flags
- Environment variables (
VANISH_API_KEY,VANISH_API_URL) - Config file (
~/.config/vanish/config.json) - Defaults
vanish runs on Cloudflare Workers + R2 + D1. To self-host:
- Clone this repo
- Create a Cloudflare account
- Create an R2 bucket and D1 database
- Update
packages/worker/wrangler.tomlwith your IDs - Deploy:
cd packages/worker
wrangler d1 migrations apply vanish-db --remote
wrangler deployFor production mini-site URLs, route *.your-domain to the Worker. Local development uses path URLs like http://localhost:8787/s/<site-id>/.
Set SELF_HOSTED=true and DEFAULT_TIER=pro to give newly authenticated users Pro access without billing.
Product events are disabled by default. Set PRODUCT_EVENTS=true to record privacy-light funnel events without filenames, paths, tokens, keys, or content.
Password protection requires a secret of at least 32 characters:
wrangler secret put ACCESS_SESSION_SECRETManaged custom domains use Cloudflare for SaaS. Configure the Worker with:
wrangler secret put CLOUDFLARE_API_TOKEN
wrangler secret put CLOUDFLARE_ZONE_IDCUSTOM_DOMAIN_FALLBACK_HOST defaults to fallback.vanish.sh in
wrangler.toml; change it for another installation before deploying.
For the hosted GitHub Actions deployments, configure these repository secrets before merging:
VANISH_ACCESS_SESSION_SECRET
CLOUDFLARE_CUSTOM_HOSTNAMES_API_TOKEN is recommended as a least-privilege
token with zone-read and custom-hostname permissions. Until it is set,
deployment uses the existing CLOUDFLARE_API_TOKEN and resolves the zone ID
automatically.
The fallback hostname must already be configured as the Cloudflare for SaaS
fallback origin. Without these values, the domain API returns
domain_provisioning_unavailable; ordinary Vanish URLs remain functional.
CLI (npm) --HTTPS--> Cloudflare Worker (Hono)
|-- D1 (users, uploads, sites metadata, optional product events)
|-- R2 (files and site assets)
`-- Cron (cleanup expired uploads/sites)
MIT