Hosting
Deploy apps and static sites with Composal hosting. Configure services, custom domains, CDN delivery, and managed resources from your workspace.
Contents
Hosting model
Composal hosting manages your organization's apps, environments, services, and deployments. It supports public services, static sites, custom domains, CDN delivery, and runtime controls.
Managed public services receive an HTTPS hostname derived from the app, environment, service, and datacenter. You do not need to supply a --deployed-url for a service Composal manages.
Deployment regions
Use aws-us-west-2 for Oregon or aws-us-east-1 for Northern Virginia. The
hosting locations API (GET /api/v1/hosting/locations) returns the current
selectable regions. Enable a location for your app before adding a placement
there.
London lon1 and legacy Oregon or1 are retired and cannot be selected for new
placements or volumes. Existing deployment history retains its original region.
Persistent block volumes are available in both AWS regions; choose the same
region for the volume and its service. A volume can attach to one service
instance at a time and requires the stable deployment channel.
Deploy a service
Use the CLI to create a deployment and follow it while it runs.
com deploy create --app <app> --service web --env production --watch
com deploy dashboard --app <app>
Deploy a tagged or digest-pinned public Docker image without a build:
com deploy image --app grafana --service grafana --env production-west --region aws-us-west-2 --image grafana/grafana:13.2.2 --wait
Hosted source builds publish to the v2 Composal registry and deploy an immutable, verified image digest. Build runners receive credentials scoped to their isolated build repository; completing or revoking the runner lease invalidates those credentials. Existing releases keep their recorded image references for rollback.
Use the v2 Composal registry for your own images:
com deploy image --app grafana --service grafana --env production-west --image registry.composal.ai/vex/grafana:13.2.2 --wait
V2 images must belong to the app's organization and an unbound or matching app repository. Composal stores immutable repository IDs and verifies the v2 image in each deployment region; repository renames do not change a release's image. Hosting credentials grant pull access only.
Docker Hub shorthand follows Docker's normal rules: redis:7 resolves to
docker.io/library/redis:7, and grafana/grafana:13.2.2 resolves to
docker.io/grafana/grafana:13.2.2. Other public registries use a full reference,
such as ghcr.io/owner/image:tag. Private external registry credentials are not
currently supported. Composal verifies the image in the deployment region and
pins its digest before replacing instances. Composal registry images retain
organization and app ownership checks.
Compatible deployments can share a build or reuse a retained image. Composal checks the exact source revision, build settings, builder runtime and delivered build-secret versions, then verifies the retained image by its immutable digest. Rotating or editing a build secret requires a new build; unavailable credentials block deployment.
Each deployment still creates its own release with its selected environment's runtime settings. The deployment page links to the producer and its build logs. A reused image shows a skipped build, while rollout progress belongs to the new deployment. If a shared producer fails or is canceled, waiting deployments return to normal build orchestration.
In the web app, you can inspect your organization's applications, environments, services, deployment history, and runtime controls.
Preview environments
A preview is a short-lived copy of an app built from one source revision. A preview profile holds its defaults: the source environment to copy, variables, build inputs, credentials and expiry. Each preview records its source revision and configuration snapshot and has its own deployment and runtime. Organization members can inspect previews; administrators manage their configuration and lifecycle. Preview URLs require organization membership unless an administrator explicitly makes the preview public.
Set up PR previews for Verify
With a preview profile, Composal Verify creates, builds and deploys a preview of each pull request's commit itself, then runs your Scenarios against it. You do not need a separate Verify environment pointing at a preview URL. You need an organization administrator and a Verify project with its GitHub repository added under PR Testing → Add repositories.
-
Create an app linked to the project's repository, and a service for each process. Verify opens one public service; workers stay internal.
Bashcom app create --project <project> --body-json '{"slug":"shop","name":"Shop","root_path":"."}' com service create --app shop --slug web --public --internal-port 3000 --healthcheck-path /health --source-path . com service create --app shop --slug worker --source-path .A root path of
.overlaps every other app on the repository. Use a subdirectory root when one repository needs several apps. -
Commit a
Dockerfilein each service's source path. Previews always build from source, using the source path as the build context. -
Create a source environment and deploy every service to it once. A preview copies only the services placed in its source environment.
Bashcom hosting location locations --json com env create --app shop --body-json '{"slug":"staging","name":"Staging","kind":"staging","status":"active","location_id":"<location-id>","auto_deploy":false}' com deploy create --app shop --service web --env staging --watch com deploy create --app shop --service worker --env staging --watch -
Create the preview profile. Verify-created previews deploy without anyone approving shared configuration, so give the profile a value for every key the app reads, and every build argument:
Bashcom preview-profile create --app shop --body-json '{"name":"PR previews","slug":"pr","source_environment_id":"staging","ttl_days":3,"configuration":{"variables":{"NODE_ENV":"production"},"build_variables":{"VITE_API_BASE":"/api"},"required_keys":["DATABASE_URL"]}}'A source-environment or app-wide variable that the profile does not cover blocks deployment with
Preview needs sharing approval for configuration. -
Bind credentials to the profile instead of putting them in variables. An app-wide secret that is not bound or masked blocks deployment.
Bashcom hosting preview-profile-secret-binding create --app shop --path preview_profile_id=pr --body-json '{"env_key":"DATABASE_URL","secret_id":"<secret-id>"}' com hosting preview-profile-secret-binding create --app shop --path preview_profile_id=pr --body-json '{"env_key":"STRIPE_SECRET_KEY","mode":"masked"}' -
Try the profile with a manual preview, then delete it:
Bashcom preview create --app shop --body-json '{"name":"Profile check","slug":"profile-check","app_preview_profile_id":"pr","source_ref":"<branch>"}' com preview deploy --app shop --id profile-check com preview operations --app shop --id profile-check com preview delete --app shop --id profile-check -
Save PR testing with the profile and the public service, then follow Composal Preview:
Bashcom verify pr-testing setup --project <project> --previews composal --preview-profile pr --service web --accounts <environment> --pr-check --on
Manage previews
Open an app's previews to create a preview from a source environment or a Change. Preview defaults control automatic Change provisioning.
Pause a preview and wait for cleanup before changing its secrets, backing connections, placement or resource limits. Compare its configuration with production, review any source drift and approve the selected sharing before deployment. Shared secret references follow the selected version policy; copying a secret creates a separately managed preview secret. Rotating a build secret requires a fresh build. Redeploy the selected preview to deliver new secret versions to its runtime.
Explicitly shared managed data connections use their authorized managed secret version for both public and provider-private URLs. An attached VPC takes precedence for the private URL. Changing private endpoint availability requires reviewing the source again; an unavailable or malformed selected endpoint blocks deployment.
Explicitly selected bucket connections share the bucket's managed access-key JSON under the same environment key as the source. The payload includes the access key, secret key, endpoint, bucket and region. Local overrides and masks retain precedence; sharing runtime bucket credentials does not expose them to builds. Rotating an access key requires redeploying the selected preview. New or rotated environment bucket credentials stay scoped to that environment.
Preview storage mounts require explicit selection. You can share a captured ephemeral source cache, or provision a compatible volume in the preview environment and select it for the captured mount. Production data volumes cannot be shared with a preview writer. The mount keeps the source path and read-only setting. A single-writer volume requires one service, one instance and compatible placement and rollout settings. Source refresh clears storage selections so you can review them again.
Pausing preserves preview-owned volumes. Deletion, expiry and Change closure stop workloads before destroying preview-owned volumes and their data. Referenced shared resources remain available; cleanup refuses to destroy a volume referenced by another consumer. Retain a preview before Change closure or expiry to keep it available, and inspect lifecycle history for cleanup progress and retryable failures.
For GitHub PR testing, choose an existing profile in Verify → Integrations → GitHub → Composal Preview. Verify provisions and deploys the PR head, then waits for healthy rollouts and its HTTPS URL. See Source Control for configuration and release availability.
Preview networking, URLs and volumes
What a preview contains:
- Each service runs one instance in one region.
- Release and prestart commands do not run. Run any database migrations when the process starts.
- Volumes and data-resource connections are not attached unless an administrator selects them for that preview. Previews that Verify creates have none, so a service starts without its volume.
- Service bindings are not carried into the preview, so their URL variables are absent.
Each public service in a preview gets its own hostname,
pv-<token>-<service>-<app>-<org>.app.vex.so, shortened when long. The token is
assigned when the preview is created. com preview show lists the preview's URLs
once its rollout finishes.
No environment variable gives a service its own preview URL or the address of
another service in the same preview. Private service names are
<service>.<app>.internal on port 8444, and a preview copy is
<service>.<app>-<token>.internal, so a profile cannot hold them. Serve the
browser app and its API from one public service, call the API with relative
paths, and build emailed links from the incoming request's origin.
A service with a persistent volume needs the stable deployment channel and a
single instance. The default channel is blue_green.
For email sign-in tests, the app must send real mail. Verify follows a sign-in
link only when its origin is the preview's URL, the test account's login URL, or
an origin listed in the account's email_link_auth_origins.
Domains and delivery
Composal can attach custom domains, validate ownership, and expose CDN delivery state. Static-site deployments have their own upload and finalization path, while managed services use the platform’s public TLS routing after the API verifies that a domain belongs to the selected app service.
Inspect runtime state
Use deployment logs and the dashboard for the current allocation and service state.
com deploy logs --app <app> <allocation-id> --task web
com deploy dashboard --app <app>
For container-image workflows, use Composal registry. For the server contract, consult the OpenAPI reference.
See the Remote builders guide for upcoming organization-managed builders with persistent layer caches, native Docker connections, and direct pushes to registry.composal.ai. The implementation is in review, the Unix supervisor is implemented, and production gateway deployment is unfinished.