Migration outcome
A reviewed, tested, and recoverable schema change
Complete this workflow before applying an Agent Barn application database migration to a shared environment.
- The repository has one continuous Alembic revision graph.
- The migration has been reviewed against realistic PostgreSQL data.
- The application image, schema, contents, and backup form one release contract.
- Staging verification and a tested production recovery path are complete.
Overview
Agent Barn uses Alembic with SQLModel metadata to version the schema of its application PostgreSQL database.
Migration files live in api/migrations/versions/. The migration environment in api/migrations/env.py imports the domain models before exposing their shared SQLModel.metadata.
Alembic normally connects through DB_CONNECTION_URL. The target database therefore matters whenever you inspect, generate, apply, or reverse a migration.
What Agent Barn migrates
The self-hosted stack contains multiple PostgreSQL databases. They do not share one migration system.
| Database | Schema owner | Migrated by Agent Barn Alembic |
|---|---|---|
| Agent Barn application PostgreSQL | Agent Barn API | Yes |
| LiteLLM PostgreSQL | LiteLLM | No |
| Firecrawl PostgreSQL | Firecrawl | No |
The commands in this guide affect only the database referenced by the API’s DB_CONNECTION_URL.
Before you begin
You need a checkout of the agent-barn repository, a reachable PostgreSQL database, authorization to change it, and a repository-root .env with the correct DB_CONNECTION_URL. Prepare a tested backup and a maintenance or recovery plan before an incompatible production change.
Install the API dependencies from the repository root:
cd api
uv sync
cd ..For local host commands, ensure DB_CONNECTION_URL is reachable from the host. Commands run through ./run.sh use the Docker Compose database configuration instead.
Choose a migration strategy
| Change | Examples | Recommended approach |
|---|---|---|
| Additive | Nullable column, new table, compatible index | One release may be sufficient after testing |
| Data-transforming | Backfill, normalization, identifier conversion | Test representative data and verify row-level results |
| Destructive | Drop or rename a column, remove an enum value | Use an expand/contract sequence across releases |
| Long-running | Large backfill, table rewrite, blocking index | Measure in staging and plan a controlled maintenance window |
Production migrations run before the new API rollout. During a pre-upgrade migration, the previous API may still serve requests, so the migrated schema must remain compatible with it until replacement.
Use expand and contract for breaking changes
- Expand: add the new schema while preserving the old schema.
- Migrate: backfill data and make the application support both representations.
- Switch: move reads and writes to the new representation.
- Contract: remove the old schema in a later release.
Inspect migration state
Run direct Alembic commands from api/ so the repository configuration and migration directory resolve correctly.
cd api
uv run python -m alembic currentcd api
uv run python -m alembic headscd api
uv run python -m alembic history --verboseThe repository expects exactly one head. Run the canonical check from its root:
make check-migrationsIf the database is behind the repository head, determine why before generating another revision. Autogeneration against an outdated or incorrect database can produce misleading operations.
Create a migration
Update the relevant SQLModel models first. When adding a model module, ensure the migration environment imports it before SQLModel.metadata is evaluated.
make makemigrationsEnter a short message when prompted, such as add agent retention policy. Alembic creates an autogenerated revision under api/migrations/versions/ with a filename resembling <revision>_add_agent_retention_policy.py.
The revision defines revision, down_revision, branch_labels, depends_on, upgrade(), and downgrade().
Review the migration
Read the entire generated revision before applying it. Confirm down_revision targets the intended current head, the graph remains continuous, and make check-migrations reports one head.
Review generated operations
- Unexpected table or column deletion, or a rename represented as drop and add
- Nullability changes without a backfill and unique constraints existing data may violate
- Foreign keys, indexes, and table rewrites that may conflict with rows or hold locks
- Server defaults, PostgreSQL enums, and type changes that require an explicit
USINGexpression - Missing application fields or operations caused by connecting to the wrong database
Review data transformations
Make transformations deterministic and safe for the expected volume. Account for malformed values, intermediate uniqueness, stable ordering, foreign keys, lock duration, and transaction failure. A uniqueness migration may require a collision-free temporary state.
Review the downgrade
Reverse the revision intentionally when reversal is safe. If a downgrade destroys data or cannot reconstruct the old representation, document that limit, test the real recovery strategy, require a backup, and prefer a forward corrective migration after production data changes.
Resolve multiple heads
Multiple heads usually appear when branches independently add revisions from the same parent. Inspect both branches before merging:
make check-migrations
cd api
uv run python -m alembic heads
uv run python -m alembic history --verboseConfirm that both branches are compatible, especially when they touch the same table, constraint, column, enum, or data set. Then create the merge revision from the repository root:
make merge-headsThe command fails when no heads exist, does nothing with exactly one head, and creates a merge revision only for multiple heads. A merge revision normally has multiple down_revision values and empty upgrade and downgrade functions.
Test the migration
Test against PostgreSQL, not an approximation. The API suite starts a temporary PostgreSQL database and upgrades it to Alembic head before tests:
make check-api
make check-migrations
make test-apiAPI CI runs make check-migrations. The test path proves the complete migration chain can build a clean database.
Test existing data
Use a staging-sized or sanitized realistic copy for backfills, constraints, enum or type changes, identifier rewrites, destructive operations, and work that may hold long locks. Verify both schema and affected rows.
Test downgrade and reapplication
make rollback
make migrateConfirm the prior revision, old-application compatibility, data preservation, successful reapplication, and the final upgraded result. make rollback runs alembic downgrade -1; do not use it casually on a shared database.
Use an isolated database override
cd api
ALEMBIC_DB_URL='postgresql+psycopg2://USER:PASSWORD@HOST:PORT/DATABASE' \
uv run python -m alembic upgrade headALEMBIC_DB_URL overrides the normal connection for isolated migration tests. Use secret injection rather than placing production credentials in shell history.
Apply migrations locally
Full local stack
./run.shThe script starts PostgreSQL and Redis, builds the API image, runs alembic upgrade head in a temporary API container, then starts the API, worker, and UI. Application services do not start when migration fails.
Host-managed development
make migrate
cd api
uv run python -m alembic currentDo not mix host-managed services and the full Docker application stack against the same development workflow unless you deliberately understand the process and database used by each command.
Deploy to staging
Pass every schema-changing release through agent-farm-staging. Confirm it has independent application data and credentials, a current backup, one Alembic head, recorded start and target revisions, and an explicit recovery choice.
The API chart creates an agentbarn-api-migrate pre-install/pre-upgrade Job. It uses the target API image and runs:
cd /app/api && alembic upgrade headThe Job must complete before Helm rolls out the new API. After deployment, verify API health, administrator login, the changed behavior, workers, Event Deliveries, Activity, Tool Calls, logs, costs, restart recovery, migration duration, and observed locking.
Deploy to production
Confirm the exact commit and API image, one Alembic head, representative staging results, backward compatibility with the old API, a verified application database backup, the matching AGENT_TOKEN_ENCRYPTION_KEY, and named verification and recovery owners. Prevent overlapping deployments and communicate any maintenance window.
The migration Job has backoffLimit: 2. Successful hook Jobs are deleted; failed Jobs remain for diagnosis.
kubectl get job agentbarn-api-migrate \
--namespace agent-farm
kubectl describe job agentbarn-api-migrate \
--namespace agent-farm
kubectl logs job/agentbarn-api-migrate \
--namespace agent-farmkubectl get pods \
--namespace agent-farm \
--selector app.kubernetes.io/component=migration-jobDo not repeatedly redeploy until you know whether the failed attempt committed schema or data changes.
Verify the migration
Check the database revision from the deployed production API environment:
kubectl exec \
--namespace agent-farm \
deployment/agentbarn-api \
-- sh -c 'cd /app/api && alembic current'Confirm it matches the release head, then check the public API using the actual production hostname:
curl --fail https://api.agentbarn.example.com/api/v1/healthVerify API and UI health, changed behavior against old and new records, Organization isolation, authorization, workers, reconciliation, affected Agent lifecycle operations, telemetry and cost ingestion, database connections, error rates, schema-related logs, migration duration, and unexpected locks.
Record the starting and target revisions, deployment commit and image, start and finish time, backup identifier, verification results, and corrective actions.
Rollback and recovery
| Situation | Preferred response |
|---|---|
| Migration did not start | Fix deployment configuration and retry |
| Migration failed and transaction rolled back cleanly | Diagnose the error, correct the migration, and redeploy |
| Migration succeeded but new API failed | Keep or restore an application version compatible with the migrated schema |
| Migration introduced a correctable schema problem | Create and deploy a forward corrective migration |
| Tested downgrade is safe and data-preserving | Run the controlled downgrade procedure |
| Migration destroyed or irreversibly transformed data | Stop writes and restore the verified recovery set |
| Database state is uncertain | Pause deployment and inspect revision, schema, data, and migration logs |
Application rollback
A Helm rollback changes Kubernetes manifests and images. It does not run alembic downgrade. Confirm the older image can use the migrated schema before restoring it.
Alembic downgrade
make rollbackThis downgrades one revision using the locally configured database. A production downgrade needs a reviewed procedure, a precise target, representative testing, understood data-loss behavior, controlled writes, application compatibility, and a current backup.
Database restoration
- Stop or isolate writers.
- Preserve logs and the failed database for investigation.
- Restore the application database backup.
- Restore the matching stable encryption key when rebuilding the environment.
- Deploy an image compatible with the restored revision.
- Verify the Alembic revision and run application and data-integrity checks.
- Reopen traffic only after verification succeeds.
Command reference
Run Make targets from the repository root.
| Command | Purpose |
|---|---|
make makemigrations | Prompt for a message and generate an autogenerated revision |
make migrate | Upgrade the configured database to head |
make rollback | Downgrade the configured database by one revision |
make merge-heads | Create a merge revision when multiple heads exist |
make check-migrations | Fail unless the repository has exactly one Alembic head |
make test-api | Run API tests against PostgreSQL migrated to head |
./run.sh | Start the local stack and migrate before starting application services |
Run direct inspection commands from api/.
| Command | Purpose |
|---|---|
uv run python -m alembic current | Show the revision applied to the configured database |
uv run python -m alembic heads | Show the repository’s current migration heads |
uv run python -m alembic history --verbose | Show the revision graph and migration history |
uv run python -m alembic upgrade head | Apply all pending migrations |
uv run python -m alembic downgrade -1 | Reverse one revision |
Operational safety checklist
Before production
- One Alembic head and a manually reviewed revision
- Upgrade testing against representative PostgreSQL data
- Tested downgrade or forward-recovery behavior
- Old-API compatibility and verified staging deployment
- A recoverable backup with matching stable keys
- Recorded revisions, deployment controls, and available owners
After production
- The database reports the expected revision
- API and UI health checks pass
- Changed data and behavior are verified
- Workers and reconciliation are healthy
- Logs contain no unexplained schema errors
- The release record contains backup and verification results
Troubleshooting
| Symptom | Likely cause | Resolution |
|---|---|---|
| make check-migrations reports multiple heads | Parallel branches created migrations from the same parent | Review both branches for conflicts, then run make merge-heads |
| Autogeneration wants to drop unrelated tables | Alembic loaded incomplete model metadata or connected to the wrong database | Verify model imports and DB_CONNECTION_URL before keeping the revision |
| Autogeneration creates no operations | The model was not imported or the database already matches it | Check api/migrations/env.py, model registration, and the target database |
| Migration cannot connect locally | DB_CONNECTION_URL is missing or not reachable from the host | Correct the repository-root .env or run through the Docker workflow |
| Migration fails on existing rows | A new constraint or type conflicts with production-shaped data | Add a validated backfill or split the change into expand and contract revisions |
| A unique backfill collides | Intermediate values violate an existing unique constraint | Use a deterministic collision-free intermediate state |
| Kubernetes upgrade stops at the migration hook | The Alembic Job failed before application rollout | Inspect the retained Job and pod logs before retrying |
| No successful migration Job exists to inspect | Successful hook Jobs are deleted | Verify alembic current from the running API pod |
| Helm rollback leaves the application broken | The database remained at the newer revision | Deploy a compatible image, run a tested downgrade, or restore the database |
| Old API fails during the pre-upgrade hook | The migration was not backward-compatible | Restore service, then redesign the change using expand and contract |
| Migration is much slower in production | Staging data volume or lock behavior was not representative | Stop repeated attempts, assess locks, and schedule a controlled migration |
| make rollback affects the wrong environment | The configured connection targeted another database | Stop, preserve evidence, assess changes, and recover from the appropriate backup |
| LiteLLM or Firecrawl schema is unchanged | Agent Barn Alembic does not manage those databases | Follow the migration process supplied by the owning upstream service |