Runtime and source builds
Build the platform runtime from source and deploy it to your Cloudflare account, by hand or from CI.
On this pageDeploy your own runtime · Add GitHub webhook ingress · Deploy source builds from CI
Deploying your runtime
Requires: login or token
Installing or upgrading a platform needs Cloudflare credentials.
This step builds the runtime. In a Git checkout, the build records the current commit in the manifest. Uncommitted changes add a -dirty suffix.
vp run build:coreExample output: The core packages and runtime built in packages/platform/dist/runtime.
Build systems may set VOID_PLATFORM_SOURCE_REVISION when they need to override automatic detection with another immutable revision. A source archive without Git metadata builds normally but leaves the revision unrecorded.
The runtime lands in packages/platform/dist/runtime. This step previews a new installation from those files with the built CLI.
void-dev platform install \
--name my-team \
--application-domain example.app \
--zone example.app \
--runtime packages/platform/dist/runtime \
--planExample output: A preview of the planned changes. Nothing is applied yet.
Before applying the plan, complete the installation guides. Run the command without --plan to install. For testing before your domain is ready, replace --application-domain and --zone with --workers-dev; PostgreSQL and the runtime, login-provider, and R2 credentials are still needed. Use void-dev in place of void and keep --runtime packages/platform/dist/runtime on install and resume commands. For an interrupted installation, keep that runtime build available until it completes.
Later, run void-dev platform domain set example.app. Domain setup uses the existing installed runtime and needs no --runtime, rebuild, or app redeploy. It keeps the platform API URL and original workers.dev app URLs available.
This step previews an upgrade for an existing installation by its ID.
void-dev platform upgrade <installation-id> \
--runtime packages/platform/dist/runtime --planExample output: A preview of the planned changes. Nothing is applied yet.
Then run it without --plan to apply the upgrade. Source-built runtimes go through the same artifact, database, ownership, and health checks as released runtimes. The CLI preserves a disabled installation's state and records the source revision in its installation checkpoint.
Optional GitHub webhook ingress for access-protected APIs
The core installer does not deploy the dashboard, GitHub App, build Containers, or webhook ingress. Passing a source build with --runtime does not provision their infrastructure, bindings, credentials, or platform capabilities. The repository's hosted deployment scripts target Void Cloud; they are not a general setup procedure for adding these services to a self-hosted platform. Use the core CLI deployment workflow unless your fork supplies and maintains that optional integration.
If your fork has added managed GitHub builds and Cloudflare Access protects its API hostname, GitHub cannot deliver directly to /webhooks/github: GitHub does not present your Access credentials. Do not add an Everyone or bypass policy to the API application.
Deploy the optional webhook ingress at a separate public hostname. It accepts signed GitHub deliveries at POST /github and forwards them to your API through a service binding. Without Access protection, use the API’s /webhooks/github endpoint directly.
To deploy the optional ingress:
Provision the GitHub App, build executors, API bindings, credentials, and managed-build capability in your fork, then deploy its source API runtime with the internal operation. A core install or upgrade alone does not add managed builds.
Edit
platform/packages/api/wrangler.github-webhook-ingress.jsonc. Give the ingress a name unique to the installation and set itsAPIservice binding to the exact installed API Worker name. Keep its public hostname separate from every human/API hostname covered by Access.Deploy it from the repository root:
shvp run --filter @voidcloud/api deploy:github-webhook-ingress --env productionExample output: The webhook ingress Worker deployed.
Use
--env stagingfor the staging entries in the same config.In the Cloudflare dashboard, add encrypted Worker secrets. Set the GitHub App's existing
GITHUB_WEBHOOK_SECRETon both the API and ingress Workers. Generate a separate high-entropy value, such asopenssl rand -base64 32, and set it asGITHUB_WEBHOOK_INGRESS_SECRETon both Workers. Do not reuse a platform management, JWT, Access, or GitHub webhook credential for that value.In the GitHub App settings, keep Content type set to
application/json, keep the same webhook secret, and change Webhook URL to the isolated ingress URL ending in/github. Use GitHub's test delivery and confirm a 2xx response before relying on push builds.
The ingress accepts payloads up to 25 MiB. See GitHub’s payload limit.
Deploying source builds from CI
Build @void/platform from your checkout and pass its runtime directory to install, upgrade, repair, enable, or rollback with --runtime. Custom runtimes get the same integrity, migration, health, and rollback checks as packaged releases.
Use a clean Git checkout or set VOID_PLATFORM_SOURCE_REVISION to identify the revision you deploy.
A fresh CI runner can discover the installation each time. Set CLOUDFLARE_API_TOKEN and VOID_PLATFORM_DATABASE_URL in its protected environment first.
CI commands and recovery inputs
Run these steps in the same shell session of one CI job. Later steps use the variables exported in step 2.
Build the core packages and the runtime.
shvp run build:coreExample output: the runtime built in
packages/platform/dist/runtime.Export a temporary registry directory and a recovery key for this run.
shexport VOID_PLATFORM_REGISTRY_DIR="$RUNNER_TEMP/void-platform-registry" export VOID_PLATFORM_RECOVERY_KEY="$(openssl rand -base64 32)"Example output: no output.
Discover the installation. This step uses the variables from step 2 and
CLOUDFLARE_ACCOUNT_IDfrom the CI environment.shnode packages/void/dist/cli/cli.mjs platform discover --account "$CLOUDFLARE_ACCOUNT_ID" \ --installation "$VOID_PLATFORM_INSTALLATION"Example output: the discovered installation.
Preview the upgrade. This step uses the installation discovered in step 3 and the runtime from step 1.
shnode packages/void/dist/cli/cli.mjs platform upgrade "$VOID_PLATFORM_INSTALLATION" \ --runtime packages/platform/dist/runtime --planExample output: a preview of the planned changes. Nothing is applied yet.
Apply the upgrade previewed in step 4.
shnode packages/void/dist/cli/cli.mjs platform upgrade "$VOID_PLATFORM_INSTALLATION" \ --runtime packages/platform/dist/runtime --yesExample output: upgrade progress, then the upgraded installation.
Omit the installation selector only if the account has one discoverable installation. Run one deployment per installation at a time, and let it finish before starting the next. Cancelling during migrations or Worker rollout can leave an installation waiting for recovery.
Keep the management token, database URL, JWT signing secret, email signing secret for email-enabled installations, and complete project-encryption keyring in a protected CI environment. Upgrades inherit deployed Worker secrets. The original values are needed when recreating a missing Worker; configuration credentials are also needed when explicitly rotating them.