Deployment
void deploy builds your app, creates resources, applies migrations and uploads the app to the saved target.
On this pageDeploy to an SDK platform · Deploy straight to your own Cloudflare account · Check deploy flags
void deploy
void deploy [--project <name>] [--dir <path>] [--spa] [--skip-build] [--debug]
void deploy [--platform <cloudflare|void>] [--require-email]
void deploy --platform cloudflare --atomic
void deploy --platform cloudflare --provisionAuto-detects your project type and chooses the right pipeline. See Supported App Types and Deployment for details.
Deploying to an SDK platform needs an explicit connection with void connect <url>. A saved project URL or VOID_API_URL alone is not a connection. In a fresh CI environment, run void connect "$VOID_API_URL" --no-login first.
On an SDK platform, an accepted deploy keeps running if the CLI disconnects. The CLI reconnects to its progress on its own. Ctrl+C only stops watching. Use void project cancel to request a cancel and void project status to see the result. If an interrupted deploy needs recovery, wait for the result before you deploy again.
The CLI reports stalled progress and automatic recovery. It waits up to 30 minutes after acceptance. If it times out, the deploy may still continue. Check void project status before you try again.
For an existing Void Worker, void deploy can link the Worker and migrate its root Cloudflare config. Keep the first deploy limited to the existing app. See Deploy an existing Worker for requirements and the ISR cache choice.
For Drizzle projects, deploy runs a read-only schema drift check. If a new migration would be generated, deploy stops. Run void db generate, review and commit the migration, then run void deploy again.
| Flag | Purpose |
|---|---|
--platform <cloudflare|void> | Override the platform stored in .void/project.json |
--project <name> | Target a specific SDK project by slug; not supported with --platform cloudflare |
--dir <path> | Deploy a pre-built static directory (skips build) |
--spa | Use SPA mode instead of SSG for static deploys |
--skip-build | Skip the build step; on Cloudflare this is supported for static/SPA/SSG deploys only |
--require-email | Fail when email cannot be set up instead of deploying without it; requires --platform cloudflare |
--provision | Run resource provisioning again even when every resource exists, for example to enable D1 read replication on an existing database; requires --platform cloudflare |
--atomic | Publish an existing Durable Object Worker directly; readiness is checked after traffic changes |
--debug | Mirror the structured deploy log to stderr (also written to ~/.void/logs/) |
--atomic applies to one deploy. If an existing Durable Object Worker can never be staged, set deploy: { cloudflare: { mode: 'atomic' } } in void.config.ts. Plain void deploy then publishes atomically. The default is staged.
Every deploy writes a JSONL log to ~/.void/logs/. On failure, the CLI prints the log path and key details. Use --debug or VOID_DEPLOY_DEBUG=1 to copy the log to stderr.
Keep credentials out of build commands. Store them as CI secrets so your CI provider masks them in logs.
The CLI picks the platform in this order:
--platform <cloudflare|void>platformin.void/project.json- The SDK for projects initialized by an older SDK without a saved platform
Choosing Skip deployment setup stores "platform": "none". A later void deploy stops and explains what to do until you pass a platform.
On the SDK platform, the CLI picks the project in this order:
--project <name>VOID_PROJECT- linked project in
.void/project.json
If no project is linked and none is passed, the CLI asks you to link or create one. In CI, void deploy fails instead. Set VOID_PROJECT or pass --project <slug>.
This step deploys to another connected SDK platform for one command only.
Requires: login to the destination
The CLI may open your browser to sign in to the destination. Credentials go to your system keychain, not your project.
Now you will connect the project to a deploy destination and deploy to a second platform for one command.
void connect second.example.com
VOID_API_URL=https://second.example.com void deploy --platform void --project my-appExample output: The CLI confirms the destination. It opens a browser sign-in if needed. Build and upload progress for my-app, then the deployment URL on that platform.
VOID_API_URL selects the platform. --project selects its project. You must name the project when you override another platform's saved link. Existing project links and deploy preferences stay unchanged, even if the target project is created. The same holds for VOID_PROJECT and for another project on the current platform. A first deploy still links the project when no destination is set. See Deploy to another SDK platform.
void deploy --platform cloudflare
This section builds and deploys to your own Cloudflare account, using void.config.ts. Now you will deploy to Cloudflare. The second command stops if email is not set up.
void deploy --platform cloudflare
void deploy --platform cloudflare --require-email # fail instead of deploying without emailExample output: Build and upload progress, then the live URL. The deploy fails with an email setup error if email is missing. Otherwise you get the live URL.
The SDK signs you in through your browser when needed and saves the account you pick. In CI, set CLOUDFLARE_API_TOKEN as a secret. If the token can reach several accounts, also set CLOUDFLARE_ACCOUNT_ID.
| Option or setting | Cloudflare behavior |
|---|---|
--dir, --spa | Deploy static output through a small Worker and Workers Assets |
--skip-build | Reuse existing static, SPA, or SSG output; unavailable for Worker apps |
--project | Unavailable; the Worker and account come from void.config.ts and void.lock.json |
| Named environments | Unavailable; use the top-level cloudflare config |
CLOUDFLARE_WORKERS_SUBDOMAIN | Needed in fresh CI when versions have no preview URL; cached locally after a deploy |
--require-email | Fail instead of deploying without email when the email step cannot run, as in CI |
DATABASE_URL | Required in the deploy environment for PostgreSQL or MySQL provisioning and migrations |
The token needs Workers Scripts: Edit, read access to bound resources and edit access to products the SDK creates. After the first deploy, commit void.lock.json before you use other machines or CI.
Use void secret put <NAME> for production server values. Local .env values are never deployed. Run void db generate and commit schema changes before you deploy.
Sandbox needs Workers Paid, Docker and Containers access. API tokens need Account / Containers: Edit and Account / Cloudchamber: Edit.
For email, set email.from and run void email setup --platform cloudflare locally. Commit the lock file. Pass --require-email in CI. See Email setup.
For Access credentials, Hyperdrive permissions, readiness and rollback, see Cloudflare deployment.