Deployment
Checked first, never forced.
Every deploy runs vage check and vage build first, shows you its plan, and asks before it changes anything. Use --dry-run to see the plan, and --yes once you've reviewed it. A deploy only reports success when the live site answers.
Cloudflare Workers (recommended on Cloudflare)
Cloudflare now hosts new static sites as Workers. Set the target once:
// vage.config.ts
deploy: { target: "cloudflare-workers", cloudflareWorker: "my-site" },npx vage deployvagejs uploads a new version and switches all traffic to it, so a custom domain never goes offline during a deploy. Your 404 page, redirects (as real 301s) and security headers all work.
Custom domains: add a wrangler.jsonc with your routes. vagejs uses it, shows its Worker name in the plan, and refuses to deploy if the file points at a different Worker or folder than expected:
{
"name": "my-site",
"compatibility_date": "2026-10-01",
"routes": [{ "pattern": "example.com", "custom_domain": true }],
"assets": { "directory": "dist", "not_found_handling": "404-page" }
}Sign in with npx wrangler login, or set CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID.
GitHub Pages
npx vage deploy:github --remote https://github.com/you/site.git # first push
npx vage deploy # target: github-pages (the default)deploy:github refuses to commit secret-looking files, dist/ or node_modules/, and never force-pushes. deploy adds a GitHub Actions workflow that checks, builds and publishes, then waits for GitHub to confirm. GitHub Pages needs a custom domain or a <user>.github.io repository.
Cloudflare Pages
npx vage deploy --target cloudflare-pages --project my-siteFor existing Pages projects. Branches other than production get their own preview address. For new sites, use Workers.
After you deploy
npx vage verify # the live site matches your files
npx vage indexnow --changed-since HEAD~1 # tell IndexNow search engines what changedverify catches anything on the live site that isn't in your project, such as injected links, scripts or pages. IndexNow needs a key in integrations.indexNow and is a hint, not a guarantee of crawling.