Skip to content
prod e051e98
Browse

1 · Compare the schema

Objective — before touching anything, find out exactly what the new release will change in the database, so a quiet DROP COLUMN or DROP TABLE can never reach production by surprise.

A vendor update is two things at once: new files and new migrations. The files you can branch and revert. The migrations touch live data — and that is where the irreversible damage hides. Comparing the schema first answers one question with certainty: “what will change, and can any of it lose data?”

You compare against your frozen baseline — the author-vX.X.X snapshot you tagged when you first imported the app. Laravel migrations track intent (the files you wrote); a schema-diff tool like Atlas tracks reality (the actual tables and columns). You want both, because vendor installers and manual hotfixes can change the database without ever writing a migration file — and only a reality-based diff catches that drift.

flowchart TD
A["migrate:status<br/>what's pending?"] --> B["migrate --pretend<br/>preview the SQL"]
B --> C["atlas schema diff<br/>reality vs baseline"]
C --> D{"Outputs<br/>match?"}
D -->|Yes| E["Classify by risk"]
D -->|No| F["Schema drift —<br/>investigate"]
E --> G{"Any drop or<br/>truncate?"}
G -->|No| H["Safe to apply"]
G -->|Yes| I["Back up + get approval"]

Before any command, find out what the vendor says changed. The changelog tells you which tables and features to expect in the diff — so an unexpected change stands out instead of blending in.

  1. Note what the release claims to touch. New tables, renamed columns, dropped features, security patches. Write the short list somewhere you’ll see it while diffing.

    • ✅ You have a one-line summary of what the vendor says this release changes in the database.

A changelog is a claim, not proof — the diff in the next steps is what you actually trust. But reading it first turns the diff from a wall of SQL into a checklist you can confirm against.

Find every migration the new release will run but yours has not. This is the file-level view: what the vendor intends to do.

  1. Check migration status, then isolate the pending ones.

    Terminal window
    php artisan migrate:status --no-ansi
    php artisan migrate:status --no-ansi | grep "No"
    # Expected: every "Ran? No" row is a migration this update will apply
    • ✅ You have the list of pending migrations; an all-Ran? Yes result means there’s nothing new at the file level (skip to step 4).
  2. Document each pending migration — its file, what it creates or alters, and a first-pass risk read.

    FieldExample
    File2024_11_02_add_timezone_to_users_table.php
    Touchesusers table — adds timezone column
    RiskLow (ADD COLUMN)
    • ✅ Each pending migration has a row capturing file, what it touches, and a first risk read.

--pretend prints the SQL a migration would run without running it. This is the safest way to read intent — no rows change, but you see every statement.

  1. Print the migration SQL without executing it, and save the output to compare against the Atlas diff.

    Terminal window
    php artisan migrate --pretend
    # Expected: the CREATE / ALTER statements that WOULD run — nothing is applied
    • ✅ You have the exact SQL Laravel intends to run, saved for the match check in step 5.

Atlas compares the actual database state against your tagged baseline. This catches changes that never appear in a migration file — installer-created tables, manual SQL, vendor scripts.

  1. Diff the post-update state against your frozen baseline tag.

    Terminal window
    atlas schema diff \
    --from "atlas://CUSTOJO?tag=author-vX.X.X" \
    --to "atlas://CUSTOJO?tag=author-vY.Y.Y"
    # Expected: a list of CREATE / ALTER / DROP statements — the real delta
    • ✅ Atlas prints the concrete schema delta between your baseline and the new release.
  2. Open the visual diff in the browser when the text output is dense.

    Terminal window
    atlas schema diff \
    --from "atlas://CUSTOJO?tag=author-vX.X.X" \
    --to "atlas://CUSTOJO?tag=author-vY.Y.Y" -w
    # Expected: a browser tab opens with a side-by-side visual comparison
    • ✅ The visual diff renders, making added/removed/modified tables easy to scan.

Laravel’s --pretend (intent) and Atlas’s diff (reality) should describe the same change. A mismatch means the database holds something your migrations don’t — schema drift you must explain before you apply anything.

  1. Line up the two outputs and confirm each change appears in both.

    Laravel --pretendAtlas diffMatch?
    CREATE users_zaj+ users_zaj
    ALTER settings.value~ settings.value
    (nothing)DROP old_table❌ investigate
    • ✅ Every change is present in both views; nothing appears in one but not the other.
  2. If they disagree, capture the drift as a migration rather than ignoring it — then re-diff until both views agree.

    Terminal window
    atlas migrate diff capture_drift \
    --dir "file://database/migrations" \
    --to "mysql://root:@localhost:3306/database" \
    --dev-url "docker://mysql/8/dev"
    # Expected: a new migration file describing the un-tracked change
    • ✅ Drift is captured in a migration (or explained), and a re-run of the diff shows the two views now agree.

Sort each confirmed change into a risk tier. The tier decides what happens next: low-risk changes proceed, destructive ones force a backup and explicit approval before Workflow step 2.

  1. Assign a risk tier to each change and decide the action it triggers.

    ChangeRiskAction
    CREATE TABLE🟢 LowProceed
    ADD COLUMN (nullable)🟢 LowProceed
    ADD COLUMN (not null)🟡 MediumVerify a default exists
    MODIFY COLUMN🟡 MediumTest on staging
    RENAME🟡 MediumVerify code references
    DROP COLUMN🔴 HighBack up first
    DROP TABLE🔴 CriticalBackup + explicit approval
    TRUNCATE🔴 CriticalBlock until reviewed
    • ✅ Every change has a risk tier and a decided action; no change is unclassified.
  2. Record the decision so the update has an audit trail — what changes, whether any are destructive, and whether a backup is required.

    • ✅ A short written record names the changes, flags any destructive ones, and states whether a pre-update backup is needed.

Do not mark this step done until every box below is checked.

  • 👤 Changelog read — the vendor’s claimed DB changes are noted and available while diffing.
  • 🤖 Pending migrations listedmigrate:status ran; each pending migration documented (file, touches, risk).
  • 🤖 SQL previewedmigrate --pretend output saved for the match check.
  • 🤖 Atlas diff run — the new release diffed against the author-vX.X.X baseline; driver matched.
  • 🤖 Views agree — Laravel --pretend and Atlas diff describe the same change, or drift is captured.
  • 🔀 Changes classified — every change has a risk tier; destructive changes flagged for backup + 👤 approval.