Skip to content
Backend
Skill

/django-safe-migration

Write, review, and rewrite Django migrations for PostgreSQL with zero-downtime guarantees. Use this skill whenever the user mentions migrations, Django schema changes, or deployment safety — even if they don't say "zero downtime" explicitly. Trigger on: "review this migration",

BOOST
From plugin
django-ai-plugins
1605 skills1 agent
Install
$ npx -y skills add vintasoftware/django-ai-plugins --skill django-safe-migration --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/django-safe-migration

Context preview

The summary Claude sees to decide when to auto-load this skill.

Write, review, and rewrite Django migrations for PostgreSQL with zero-downtime guarantees. Use this skill whenever the user mentions migrations, Django schema changes, or deployment safety — even if they don't say "zero downtime" explicitly. Trigger on: "review this migration",

SKILL.md

django-safe-migration.SKILL.md
name: django-safe-migration
description: >
  Write, review, and rewrite Django migrations for PostgreSQL with zero-downtime guarantees.
  Use this skill whenever the user mentions migrations, Django schema changes, or deployment safety — even if they don't say "zero downtime" explicitly.
  Trigger on: "review this migration", "is this migration safe?", "write a migration for...", "rewrite this migration", "how do I add a NOT NULL column / drop a column / add an index / rename a column / add a FK without downtime", "will this migration cause locks?", "this migration is blocking production".
  Covers: SeparateDatabaseAndState two-file splits, AddIndexConcurrently, FK NOT VALID + VALIDATE, db_default for NOT NULL columns, lock_timeout, and RunPython safety rules.

Django Migration — Zero Downtime

Project Configuration

Read the active host's project instruction file (for example, `AGENTS.md` or `CLAUDE.md`) for the values below. If they are not set, use the defaults shown.

| Key | Default | Notes | |---|---|---| | **Django version** | unknown | Affects `db_default` availability — only Django 5.0+ supports it | | **Deploy strategy** | rolling deploy | Rolling deploy is the most restrictive; blue/green or maintenance-window deploys allow more operations | | **Runtime guard** | none | If a guard is configured (e.g. `django-pg-zero-downtime-migrations`), operations it blocks are **Errors**; uncovered operations are **Warnings** | | **Migration command** | `python manage.py sqlmigrate` | e.g. `make sqlmigrate` or `docker compose run web python manage.py sqlmigrate` | | **Docs / wiki URL** | none | If set, append `#<anchor>` links when flagging issues in review output |

To configure this skill for your project, add a section like this to the active host's project instruction file:

## django-safe-migration
- Django version: 5.1
- Deploy strategy: rolling deploy
- Runtime guard: none
- Migration command: docker compose run web python manage.py sqlmigrate
- Docs URL: https://github.com/your-org/repo/wiki/migrations

---

When to Use

  • "Review this migration"
  • "Is this migration safe?"
  • "Write a migration for..."
  • "Rewrite this migration to be safe"
  • "How do I add a NOT NULL column / drop a column / add an index / rename a column / add a FK..."

---

Why Zero-Downtime Migrations Matter

In a rolling deploy, the new database schema is applied first, then application instances are restarted one by one. At any moment during the deploy, old code and new code run simultaneously against the same database.

Every migration must be safe to run while the previous version of the app is still serving traffic. A migration that takes an `ACCESS EXCLUSIVE` lock on a large table blocks all reads and writes — downtime even for a few seconds on a busy table.

The problem is not just the lock itself but the **wait queue**: a fast `ALTER TABLE` that takes 50ms will queue behind any long-running transaction, and all subsequent queries queue behind the migration. On a busy table this cascades into connection pool exhaustion.

---

How PostgreSQL Locking Works

| Lock | Acquired by | Blocks | |---|---|---| | `ACCESS EXCLUSIVE` | Most `ALTER TABLE`, `DROP INDEX`, `DROP CONSTRAINT` (FK) | All reads and writes | | `SHARE ROW EXCLUSIVE` | `ADD FOREIGN KEY` (on child table + referenced table simultaneously) | Writes only (on both tables) | | `SHARE` | `CREATE INDEX` | Writes only | | `SHARE UPDATE EXCLUSIVE` | `CREATE INDEX CONCURRENTLY`, `VALIDATE CONSTRAINT` | Nothing meaningful — safe under traffic |

For the full conflict matrix (table-level locks × business logic operations × row-level locks) and the FIFO wait-queue explanation, load `references/postgres-locks.md`. Load it when:

  • explaining *why* a specific operation is unsafe
  • a developer asks what a lock type blocks or conflicts with
  • reasoning about whether two concurrent operations interact

---

lock_timeout

Any operation that requires `ACCESS EXCLUSIVE` should be preceded by `SET LOCAL lock_timeout`. This causes the migration to fail fast (with a clear error) instead of waiting indefinitely for the lock — preventing connection pool exhaustion from queue cascading.

For a normal transactional migration:

migrations.RunSQL("SET LOCAL lock_timeout = '2s'"),
migrations.AlterField(...),  # or any ACCESS EXCLUSIVE operation

`SET LOCAL` scopes the timeout to the current transaction, so it does not affect other sessions or persist after the migration completes.

**Default**: `2s` — adjust up if the table is known to have long-running transactions that legitimately need more time, or down for stricter environments.

For `atomic = False` migrations, combine `SET LOCAL` and the DDL in the same `RunSQL` operation; see Structural Rules below.

---

Key Patterns

NOT VALID + VALIDATE (for FK and CHECK constraints)

A two-step PostgreSQL technique to add a constraint without a long lock:

1. **`ADD CONSTRAINT … NOT VALID`** — creates the constraint and enforces it on new writes immediately, but skips scanning existing rows. Takes a brief lock with no table scan — `SHARE ROW EXCLUSIVE` on both tables for FK constraints, `ACCESS EXCLUSIVE` for CHECK constraints. 2. **`VALIDATE CONSTRAINT`** — scans existing rows to confirm they satisfy the constraint. Takes `SHARE UPDATE EXCLUSIVE` (plus `ROW SHARE` on the referenced table for FK constraints), which does not block reads or writes.

The dangerous part is the full-table scan, not the constraint creation itself. Splitting it keeps the write-blocking lock window to milliseconds, with the long scan moved to a non-blocking step.

PostgreSQL docs: [`NOT VALID`](https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-DESC-ADD-TABLE-CONSTRAINT) · [`VALIDATE CONSTRAINT`](https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-DESC-VALIDATE-CONSTRAINT)

---

Runtime Guards

Some projects configure a custom database backend or linter tha

Read more
Ships withdjango-ai-plugins

Portable Django expertise for Claude Code, Codex, Cursor, OpenCode, and tools that implement the Agent Skills specification. The repository has one canonical authoring tree under skills/.

Get the whole plugin
Stats
160
Stars
27
Forks
Maintained
Maintenance
Python
Language
3mo ago
Last commit
9mo ago
Created
4h ago
Added

Repo: vintasoftware/django-ai-plugins

Other skills on django-ai-plugins.