---
id: platform/pre-deploy-commands
title: Pre-deploy commands
description: Run a finite command against a new image before releasing it, with explicit timeout, retry, filesystem, and migration constraints.
keywords: [bex, preDeployCommand, migration, deployment, release]
last_updated: 2026-09-23
---

A pre-deploy command runs after the new image is available and before Bex
releases that revision. Use it for a finite task such as a database migration
that must complete before the new application starts serving.

This step applies to web services, private services, and background workers.
It does not apply to static sites or cron jobs. Configuring executable commands
requires developer/admin permissions; permission to restart a service alone is
not enough.

## Configure the command

Add `preDeployCommand` to a [Blueprint](./app-resource.md) service declaration:

```yaml
services:
  - type: web
    name: api
    runtime: node
    repo: https://github.com/acme/api
    plan: starter
    buildCommand: npm ci
    preDeployCommand: npm run migrate
    startCommand: npm start
    healthCheckPath: /healthz
    autoDeployTrigger: off
```

This assumes your application supplies the migration/start scripts, health
endpoint, and required database configuration. Add a [datastore reference or
secret](./secrets.md) for the connection. Test the migration against disposable
data before attaching it to a real deployment.

The API also supports updating the service's pre-deploy command; an empty string
clears it. Treat a command change as a deployment-affecting configuration change,
not just a label edit. For a Blueprint-managed service, update the manifest so a
later sync does not restore the old command.

## Execution environment and limits

Bex runs `sh -c <command>` in the **new revision's image**, in a separate job.
The image must contain `sh` and all tools the command uses. The command receives
the service's environment, secret files, image-pull credentials, and resource
limits; network access still follows the applicable policy.

The job does not mount the service's persistent disk. Files written to its local
filesystem are not copied into the released service. Build required artifacts
into the image, or write to an appropriate external store when that is the
intended operation.

The current Bex job deadline is **10 minutes**. A nonzero exit or deadline failure
blocks the revision. Bex does not automatically retry the failed job, and a
completed step is not rerun for the same revision. A new deployment can execute the command again, so make the
operation safe to repeat and inspect partial changes after failure.

## Observe the result

Follow the deployment and its `predeploy` logs. A successful command allows the
release to proceed; readiness and the application's own behavior still need to
succeed afterward. If the step fails, the previous revision can remain serving
when one exists. On a first deployment there is no previous release to serve.

Finished job pods are cleaned up; durable log availability depends on the
configured [logging backend](./logging.md). Capture useful diagnostics while
investigating, without printing credentials.

## Database migration discipline

The previous application may still use the database while the command runs.
Prefer schema changes compatible with both old and new code during transition.
Assign migration ownership deliberately when several services share a database;
separate service deployments do not create a global migration lock.

A failed command may already have changed data. Before retrying, inspect the
migration tool's state and decide whether to resume, repair, or restore from a
verified backup. An [image rollback](./rollbacks.md) does not undo a schema or
data change. Long migrations that exceed the deadline need a separately planned
procedure rather than a command that launches work in the background and exits.

For command-not-found failures, check the final image and working directory.
For connection failures, check credentials, DNS, and network policy. For a timeout,
measure the migration and split or redesign it before retrying. See
[how deploys work](./how-deploys-work.md) for the complete release sequence.

A runnable old/new application rehearsal for a compatible column rename lives in
the downloadable [`postgres-schema-rollout`](/examples/postgres-schema-rollout/README.md)
sample and the guide [Rehearse a Postgres schema change](./postgres-schema-rollout.md).
