Infrastructure adapters
Infrastructure adapters
Most teams use the default Install Compose stack and never touch adapter settings. This page is for higher-scale or custom deployments, external object storage, a CDN in front of downloads, or splitting the API and worker.
Patch is an integrated product, not a plugin marketplace. Under the hood it has two fixed integration points, storage adapters and delivery adapters, that let you swap backends without changing the CLI, dashboard, or SDK.
See How it works for the end-to-end flow. This page explains what you can configure on the server side.
Two layers
| Layer | Question it answers | Env var |
|---|---|---|
| Storage adapter | Where are bundles and manifests stored? | STORAGE_ADAPTER |
| Delivery adapter | What public URLs do clients download from, and how is the cache invalidated? | DELIVERY_ADAPTER |
The API and worker read and write artifacts through the storage adapter. When a release is published, the delivery adapter resolves stable public URLs (embedded in manifests) and optionally purges a CDN cache.
The server never serves OTA artifacts from the API domain; clients fetch from your download base URL. See How delivery works.
Defaults (self-host installer)
scripts/selfhost/install.sh sets up:
STORAGE_ADAPTER=s3with bundled MinIODELIVERY_ADAPTER=base-url: clients fetch directly fromPUBLIC_BASE_URLPUBLIC_BASE_URLon your storage domain, e.g.https://storage-updates.example.com/codemagic-patch- Compose hardcodes
MODE=all(API and release worker in one process)
The cmpatch selfhost install wizard can prepare R2, S3 or GCS storage
automatically or guide you through console setup, including the selected CDN. Splitting MODE=api / MODE=worker still requires a custom
deployment; the supported Compose topology runs MODE=all.
Storage adapter
Controls where release artifacts live.
| Value | Typical use |
|---|---|
s3 | Default. MinIO in the Compose stack, or any S3-compatible store (AWS S3, Cloudflare R2, etc.) in a custom deployment |
gcs | Google Cloud Storage with separate public and internal buckets (custom deployment) |
memory | Local development and tests only, not for production |
S3-compatible storage
Used by the default self-host stack (MinIO) and for external object storage at scale.
Key variables (full list in Configuration reference):
| Variable | Role |
|---|---|
S3_BUCKET | Public bucket name (required when STORAGE_ADAPTER=s3) |
S3_INTERNAL_BUCKET | Optional distinct private bucket for _internal/ keys, including copy source and destination; unset retains one-bucket routing |
S3_ENDPOINT | Custom endpoint for MinIO or S3-compatible services |
S3_FORCE_PATH_STYLE | true for MinIO; often false for AWS |
S3_REGION | AWS region (default us-east-1) |
S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY | Credentials, or omit both to use the host's default credential chain |
PUBLIC_BASE_URL must point at the publicly readable viewer URL for artifacts:
the storage domain in a default install, or the CDN domain when fronted.
Choose S3/R2 in cmpatch selfhost install, or pass a complete runtime
configuration with --storage-mode s3|r2. New wizard installs require distinct
public and internal buckets; unset S3_INTERNAL_BUCKET preserves legacy
one-bucket server routing. Changing
only STORAGE_ADAPTER in an existing .env.selfhost is not a migration and
does not move stored objects.
On AWS, the wizard's runtime credentials are a dedicated bucket-scoped IAM user key, not an SSO or STS session. It changes only the buckets it creates. It does not turn off account-wide Block Public Access.
Google Cloud Storage
Set STORAGE_ADAPTER=gcs with:
GCS_PUBLIC_BUCKET: artifacts clients downloadGCS_INTERNAL_BUCKET: staged uploads (_internal/*); must be a different bucket
Select GCS in cmpatch selfhost install with automatic or guided setup,
or pass --storage-mode gcs with a complete two-bucket runtime configuration. The Compose
path mounts the service-account JSON supplied with --gcs-credentials-file.
Runtime access is granted on those two buckets, not the project. Public Access
Prevention must allow anonymous reads on the public bucket, and the project must
allow service-account key creation.
Delivery adapter
Controls how storage keys become client-facing download URLs and whether the server purges an edge cache after each release.
| Value | Typical use |
|---|---|
base-url | Default. URLs are PUBLIC_BASE_URL + storage key. No CDN integration. |
cloudflare | Storage domain is proxied through Cloudflare; server calls the Cache Purge API after releases |
cloudfront | CloudFront serves PUBLIC_BASE_URL; server submits scoped invalidations after releases and wildcard invalidation on deployment deletion |
With base-url, clients hit your storage domain directly (Caddy → MinIO in the default stack).
With cloudflare, manifest URLs still use PUBLIC_BASE_URL, which should be the Cloudflare-fronted storage domain, and Patch purges cached manifest URLs after releases, promotions, rollbacks, and related deployment changes. Setup: Cloudflare setup.
With cloudfront, bundled MinIO uses a separate header-protected origin
hostname while the viewer storage hostname remains PUBLIC_BASE_URL. External
S3/GCS uses the bucket endpoint directly. Setup: CloudFront setup.
Purge is best-effort: a failed purge does not roll back a release, but you may see stale bundles at the edge until the cache expires.
When adapters matter
You usually need to think about adapters when:
- Download volume or geographic reach outgrows a single origin: add Cloudflare (Cloudflare setup) or CloudFront (CloudFront setup)
- You want managed object storage instead of bundled MinIO: choose external S3-compatible storage or GCS during the first install
You usually do not need to change adapters when:
- You are evaluating Patch or running a single Docker host
- You publish through
cmpatchand the dashboard on the default installer layout
The server accepts MODE=api and MODE=worker, but the self-host Compose topology is MODE=all only. Caddy does not expose /worker/* publicly. Split API/worker is not a turnkey self-host option.
Client config stays the same
Adapter changes are server-side. Apps still need two URLs:
| App config | Points at |
|---|---|
CodemagicPatchApiUrl | API / control plane (metrics, auth) |
CodemagicPatchDownloadBaseUrl | PUBLIC_BASE_URL, storage domain or CDN-fronted equivalent |
If you add a CDN, CodemagicPatchDownloadBaseUrl should match the CDN-facing base URL clients actually fetch from, not the raw MinIO origin.
Related
- Configuration reference: all env vars
- How delivery works: manifest paths and public vs internal objects
- Cloudflare setup: DNS, CDN delivery adapter, install flags
- CloudFront setup: bundled/external origins, IAM, DNS cutover
- Install: default install
- Ongoing maintenance: backups, upgrades, health
- Operations: backup, restore, upgrade commands