Init Jobs

Init jobs run to completion before your HTTP container starts. They share the same project's secrets, registries, and volumes — making them ideal for one-shot setup tasks every time a new replica or region comes up.

Updated 8 Jun 20263 min read

Init jobs run to completion before your HTTP container starts. They share the same project's secrets, registries, and volumes — making them ideal for one-shot setup tasks every time a new replica or region comes up.

Use init jobs for:

  • Database schema migrations
  • Asset or configuration download into a shared volume
  • Waiting on external dependencies before serving traffic
  • Cache warm-up
  • Generating runtime config from secrets

Init jobs run on every pod start — first deployment, autoscaling events, restarts, and node-recovery. The main container won't start until every init job in the list has finished successfully.

How it differs from cron jobs and workers

  • Cron jobs run on a schedule, independently of any HTTP container.
  • Workers run continuously alongside the main container.
  • Init jobs are tied to an HTTP container's lifecycle and only run during pod startup.

Init jobs are available on HTTP containers only.

Configuration

Each init job has:

  • Handle — a short identifier unique within the container. Used for logs and events.
  • Image — the OCI image to run. May come from a private registry in the same project.
  • Command and arguments — optional override of the image entrypoint.
  • Environment variables — both plain key/value pairs and project secrets exposed as env vars.
  • Volume mounts — opt-in. Pick which of the parent container's persistent or ephemeral volumes to mount, and at which path. Defaults are pre-filled from the parent container's mount path.
  • CPU and memory override (advanced) — leave blank to inherit the main container's requests. Override when the init job needs more resources than the steady-state app, such as a heavy migration.

If an individual init job needs a hard time limit, wrap its command — for example timeout 600 ./migrate --up. The init job exits non-zero on timeout and the pod restarts.

Execution order

Init jobs run sequentially in the order you list them. Each one must complete successfully before the next begins. Use the up/down arrows in the form to reorder.

Limits

Each HTTP container can have up to 3 init jobs.

Pricing

Init jobs are included at no extra charge. They run before the main container starts and share the main container's reserved CPU and memory — the resources are already accounted for in the main container's hourly rate. There is no per-init-job line item on your invoice.

For this reason, init jobs use the same CPU and memory as the main container; there is no separate resource override on the init job itself.

Failure handling

If an init job fails, the pod will not start. Bahriya retries the pod start up to the platform's default retry budget; persistent failures show up in the container's Events tab and Logs tab. Filter the logs by the init job's handle to scope to a specific job.

Example

container:
  handle: my-api
  image: registry.example.com/my-api:1.0
  lifecycle:
    init_jobs:
      - handle: migrate
        image: registry.example.com/migrator:1.0
        command:
          - /bin/sh
          - -c
          - ./migrate --up
        args: []
        env:
          - { key: STAGE, value: production }
        secrets:
          - { secret: db-password, name: DATABASE_URL }
        volumes:
          - { handle: app-data, mountpath: /var/data }
        cpu: 500
        memory: 1024
      - handle: seed
        image: registry.example.com/seeder:1.0

This container starts by running migrate (a one-off migration job with extra resources). When migrate exits successfully, seed runs. Only then does the main my-api container start serving traffic.