---
id: platform/how-deploys-work
title: How deploys work
description: Understand source changes, builds, pre-deploy commands, readiness, and service-specific deployment outcomes.
keywords: [bex, deploy, build, rollout, git push, app resource]
last_updated: 2026-09-23
---

A deployment attempts to release a particular version of your application.
The service stores configuration; deployment records describe attempts to turn
that configuration and source into a running release. Saving a source setting
and releasing that source are separate operations.

![Bex deploy detail showing release status and logs](/img/dashboard/deploy-detail.webp)

## What starts a deployment

A deployment can start during service creation, from a manual deploy action,
from a Blueprint apply, or from a connected GitHub push when auto-deploy is
enabled for the branch. Build filters and the selected source affect which
pushes qualify. See [GitHub integration](./github-integration.md).

In a Blueprint, `autoDeployTrigger: commit` enables commit-triggered deployment;
`off` disables it. Bex currently rejects `checksPass` because it does not
implement that CI-check gate. A public repository URL alone does not establish
a webhook connection. An image tag changing in a registry does not itself
submit a deployment.

## Build cache {#build-cache}

Where caching is enabled, a deploy reuses the service's stored layers; see
[Build caching](./build-cache.md) for the model. To force one deploy to
rebuild every layer, clear the cache on that deploy only — the next deploy
reuses the fresh cache normally. Accepted values are the string enum
`"clear"` and `"do_not_clear"` (empty and omitted mean `do_not_clear`); with
caching disabled on the instance, both values change nothing.

Clear from any surface:

```bash
bex deploys create srv-abc123 --clear-cache
```

```bash
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $BEX_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"clearCache":"clear"}' \
  "$BEX_API_URL/v1/services/$BEX_SERVICE_ID/deploys"
```

```graphql
mutation {
  triggerDeploy(serviceId: "srv-abc123", clearCache: "clear") {
    id
    status
  }
}
```

In the dashboard, use the service's **Clear build cache & deploy** action.
See [`deploys create`](./cli-reference.md#deploys-create) for the CLI flags.

## Follow a release

1. **Queued:** the platform records the attempt and waits for build or runtime
   capacity and required infrastructure. A queued build is not yet executing.
2. **Build:** Git-backed services build the selected source. Docker builds use
   the repository's Dockerfile; native builds use the selected runtime and
   supplied commands. Prebuilt-image services skip source compilation.
3. **Pre-deploy work:** when configured for a supported workload, the
   pre-deploy command runs before the new release is promoted. A failed
   command prevents that release from proceeding.
4. **Deploy or publish:** long-running services roll out processes, static
   sites publish assets, and cron jobs update the executable and schedule.
5. **Ready or failed:** the deployment reports its result. Inspect its logs
   and status details rather than treating submission as success.

Open a deployment from the service's history to see its source revision,
timeline, and available logs. Keep build failures separate from application
startup failures: the corrective action depends on where the attempt stopped.

## What readiness means

| Service | What to verify after deployment |
| --- | --- |
| Web or private service | Its listener and [health checks](./health-checks.md) become ready; test an application request as well. |
| Worker | The process remains running; check logs and actual queue or job outcomes because there is no HTTP readiness probe. |
| Cron job | The schedule is configured; inspect individual runs separately for task success. |
| Static site | The published files are served; check the homepage, assets, and nested routes. |

An HTTP service without an explicit health path uses TCP probes. A process
accepting TCP connections can still have application-level errors, so choose
an HTTP health endpoint when you need a stronger readiness signal.

## Deployment availability

Ordinary long-running services use rolling updates. Readiness checks keep
unready instances out of service traffic, but deployment success is not a
universal zero-downtime guarantee: capacity, application behavior, shutdown,
and storage all matter. For an application that finishes accepted HTTP work
before exit, see [HTTP shutdown drain](./http-shutdown.md).

A service with a persistent disk uses a `Recreate` deployment strategy so the
old pod releases the volume before its replacement starts. Expect an
interruption for that deployment shape. A first deployment has no previous
healthy release to keep serving if it fails.

A failed build or pre-deploy command does not make the new release live.
For rollout failures, inspect the active revision and ready instances rather
than assuming the previous application is fully healthy. Use
[rollback](./rollbacks.md) when you need to restore a known release; database
migrations and external side effects are separate from an image rollback.

## Operational actions are distinct

[Restart, suspend, and resume](./app-lifecycle.md) operate an existing service
without rebuilding its source. Use deploy to release a new revision. For cron
jobs, a manual run executes the current job configuration rather than creating
a new source build.

## Troubleshoot in order

Check the selected source and branch, then build logs, any pre-deploy command,
runtime logs, and health-check results. For queued work, look for reported
capacity or infrastructure waits. For a ready service with no reachable public
URL, inspect routing and [custom-domain](./custom-domains.md) configuration.

See [Docker deploys](./docker-deploys.md), [Logging](./logging.md), and
[Metrics](./metrics.md) for the next diagnostic step.

See [pre-deploy commands](./pre-deploy-commands.md) for execution limits and migration guidance.

## My change did not ship {#change-did-not-ship}

When the running code is not what you pushed, work in order:

1. **Confirm the deployed commit.** Open the deploy row and compare its commit
   with your push; a deploy triggered before the push landed — or pinned to an
   older commit — never contained your change.
2. **Confirm the build ran.** A deploy that reused a previous image (or a
   restart, which rebuilds nothing) cannot carry new code. Check the deploy's
   build logs in [Logging](./logging.md).
3. **Clear the cache and redeploy.** If the build ran at the right commit but
   reused stale layers, trigger one deploy with the cache cleared (see
   [Build cache](#build-cache) above) and confirm the change lands.
4. **Check env changes.** If only configuration changed, confirm the new
   values are on the service and redeploy; a code-identical rebuild still
   re-runs env-dependent steps. See [Environment variables & secrets](./secrets.md).
