Deploying a migration script without reviewing it is like merging a pull request without reading the code. It works—until it doesn't. One missing NOT NULL constraint, one dropped column still referenced by a background job, one index missing from a hot query path—and your on-call rotation starts at 2 AM.
The problem is that most teams don't have a clean way to see what changed. They rely ongit diff against SQL dump files, which is noisy, error-prone, and misses semantic meaning. This post shows a better way: semantic schema comparison that tells you exactly what changed and generates the migration script for you.
Let's say you rename a column from user_name to username and add a UNIQUE constraint. A text diff of two SQL dumps might look like this:
-- Old dump
CREATE TABLE users (
id SERIAL PRIMARY KEY,
user_name VARCHAR(255) NOT NULL
);
-- New dump
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE
);
A line-by-line diff flags the entire CREATE TABLE block as changed. It doesn't tell you that a column was renamed, a unique constraint was added, or that the old column was dropped. You have to reconstruct the intent manually.
Semantic diff, on the other hand, understands SQL. It sees:
user_nameusername with UNIQUEThat semantic understanding is what lets you generate a precise, safe ALTER TABLE script instead of guessing.
Before you can compare, you need two schema snapshots: your current production schema and your proposed new schema.
PostgreSQL:
pg_dump --schema-only --no-owner --no-privileges \
postgres://user:pass@host/dbname > schema_old.sql
MySQL / MariaDB:
mysqldump --no-data --skip-comments \
-h host -u user -p dbname > schema_old.sql
SQLite:
sqlite3 database.db ".schema" > schema_old.sql
Do the same for your target schema—whether that's your local development database after running migrations, or a staging environment.
Dump files often contain noise that isn't schema structure:
SET statements and session configurationStrip these out or your diff will be flooded with false positives. The cleanest approach is to dump with flags that exclude them (--no-owner --no-privileges --no-comments in PostgreSQL) and then keep only CREATE TABLE and CREATE INDEX statements.
Paste both schemas into a semantic diff tool. Here's what you should expect to see:
ALTER TABLE statementsPrivacy tip: Your schema structure can reveal a lot about your data model. Use a tool that runs entirely in your browser so your schema never leaves your machine.
Never run a generated migration blindly. Look for these common gotchas:
VARCHAR(255) to VARCHAR(50) will truncate existing data.NOT NULL to a column with existing NULLs will fail.Even a perfect-looking migration can fail in practice due to locks, disk space, or existing data edge cases. Run the generated script against a staging database with production-like data volume before touching production.
Not all databases speak the same ALTER TABLE dialect. A semantic diff tool should generate the right syntax for your target database.
| Change | PostgreSQL | MySQL |
|---|---|---|
| Change column type | ALTER COLUMN ... TYPE |
MODIFY COLUMN |
| Add constraint | ADD CONSTRAINT |
ADD CONSTRAINT |
| Drop default | ALTER COLUMN ... DROP DEFAULT |
ALTER COLUMN ... DROP DEFAULT |
| Rename column | RENAME COLUMN |
CHANGE COLUMN |
SQLite is the most limited: it doesn't support dropping columns or altering column types directly. A semantic diff tool should warn you when a change requires recreating the table.
If you're doing this manually more than once a week, automate it. The best places to hook in schema comparison are:
You don't need to install anything. Paste two schema dumps below and see the semantic diff in seconds.
Paste your old and new CREATE TABLE statements. Get a color-coded diff and a ready-to-run migration script.
Open SchemaLensSchemaLens is a browser-based SQL schema diff tool. No signup, no upload, no backend. Your schema never leaves your machine. Try it free →