CAPYSQUASH

Docker Validation

How CAPYSQUASH uses Docker to validate schema equivalence

DOCKER VALIDATION

CAPYSQUASH uses Docker containers with PostgreSQL to validate that squashed migrations produce the same schema as your originals.

💡 Docker validation is used by CAPYSQUASH Platform, capysquash-cli, and available in pgsquash-engine library.

WHY DOCKER VALIDATION?

THE PROBLEM

How do you verify that consolidated migrations produce the same database schema?

Static analysis has limitations:

  • SQL is complex with many edge cases
  • PostgreSQL has dialect-specific behaviors
  • Extensions can change semantics
  • Sequence orders matter
  • Implicit conversions exist

The solution: Actually run both migration sets and compare the results.

THREE VALIDATION APPROACHES

CAPYSQUASH offers three Docker-based validation strategies:

TWO_CONTAINERS

Most accurate but slower

☑ Separate Docker containers

☑ Complete isolation

☑ Extension conflicts avoided

☑ Best for production

~2-3 min for 100 migrations

TWO_DATABASES

Best balance (default)

☑ One container, two databases

☑ Shared extensions

☑ Faster startup

☑ Good for most cases

~90-120s for 100 migrations

SCHEMA_DIFF

Fastest for development

☑ Single database

☑ Schema dump comparison

☑ Quick iteration

☑ Development workflows

~30-45s for 100 migrations

HOW IT WORKS

Step-by-Step Process

1

START DOCKER CONTAINERS

Spin up PostgreSQL containers (or single container with multiple databases)

docker run -d postgres:16
# Wait for ready state
2

DETECT & INSTALL EXTENSIONS

Scan migrations for required PostgreSQL extensions

-- Auto-detected
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
3

APPLY ORIGINAL MIGRATIONS

Run all original migration files in order

psql < 001_init.sql
psql < 002_users.sql
psql < 003_posts.sql
# ... continue for all files
4

CAPTURE ORIGINAL SCHEMA

Use pg_dump to capture complete schema state

pg_dump --schema-only \
--no-owner \
--no-privileges \
original_db > original_schema.sql
5

APPLY SQUASHED MIGRATIONS

Run consolidated migration files in fresh database

psql < 001_schema_foundation.sql
psql < 002_constraints_relationships.sql
psql < 003_indexes_performance.sql
# ... continue for squashed files
6

CAPTURE SQUASHED SCHEMA

Use pg_dump again on squashed database

pg_dump --schema-only \
--no-owner \
--no-privileges \
squashed_db > squashed_schema.sql
7

COMPARE SCHEMAS

Byte-for-byte diff of schema dumps

diff original_schema.sql squashed_schema.sql
# Exit code 0 = identical
# Exit code 1 = differences found
8

CLEANUP CONTAINERS

Stop and remove Docker containers

docker stop container_id
docker rm container_id

EXTENSION DETECTION

pgsquash automatically detects and installs PostgreSQL extensions:

AUTO-DETECTED EXTENSIONS

COMMON EXTENSIONS

  • vector (pgvector)
  • uuid-ossp
  • pg_stat_statements
  • pg_trgm
  • postgis
  • hstore
<div>
  <h4 className="font-black uppercase text-sm mb-3">SUPABASE EXTENSIONS</h4>
  <ul className="list-disc list-inside font-bold text-sm space-y-1 pl-4">
    <li>pg_graphql</li>
    <li>pg_jsonschema</li>
    <li>pgjwt</li>
    <li>pg_net</li>
    <li>vault</li>
  </ul>
</div>

Extensions are detected by scanning CREATE EXTENSION statements and automatically installed before running migrations.

VALIDATION OUTPUT

Success Case

🔍 Running Docker validation with TWO_DATABASES approach...

☑ Docker containers started
☑ Extensions detected: vector, uuid-ossp
☑ Extensions installed successfully
☑ Original migrations applied (287 files)
☑ Original schema captured
☑ Squashed migrations applied (12 files)
☑ Squashed schema captured
☑ Schema comparison: IDENTICAL

☑ Validation successful: Schemas are equivalent
Duration: 45.2s
Approach: TWO_DATABASES

Failure Case

🔍 Running Docker validation...

☑ Docker containers started
☑ Extensions installed
☑ Original migrations applied
☑ Original schema captured
☑ Squashed migrations applied
☑ Squashed schema captured
✗ Schema comparison: DIFFERENCES FOUND

☒ Validation failed: Schemas are different

Differences:
TABLE users:
- MISSING COLUMN: legacy_id (type: TEXT)
- EXTRA COLUMN: user_uuid (type: UUID)

INDEX idx_legacy_id:
- MISSING in squashed schema

Recommendation: Review consolidation rules and retry

VALIDATION CONFIG

Configure validation in pgsquash.config.json:

{
  "validation": {
    "docker_approach": "TWO_DATABASES",
    "enable_extension_detection": true,
    "auto_install_extensions": true,
    "enable_sql_fixes": true,
    "custom_extensions": {
      "vector": "pgvector/pgvector:latest"
    }
  }
}

WHEN VALIDATION RUNS

VALIDATION TRIGGERS

1.Manual validation command: pgsquash validate original/ squashed/
2.SAFE workflow: Automatically runs with TWO_CONTAINERS
3.FAST workflow: Automatically runs with SCHEMA_DIFF
4.CI/CD pipelines: Can be integrated into automated workflows

DOCKER REQUIREMENTS

⚠️ REQUIREMENTS

Docker Desktop (macOS/Windows) or Docker Engine (Linux) must be installed

Docker daemon must be running

Network access to pull PostgreSQL images

Sufficient disk space for Docker images (~500MB)

Available ports for PostgreSQL (default: 5432)

CHECK DOCKER STATUS:

docker ps
# Should show running containers or empty list

PERFORMANCE TIPS

🚀 SPEED UP VALIDATION

  • Use SCHEMA_DIFF for dev
  • Keep Docker images cached
  • Use local Docker volumes
  • Limit migration file count

🎯 IMPROVE ACCURACY

  • Use TWO_CONTAINERS for prod
  • Enable extension detection
  • Match PostgreSQL version
  • Include all extensions

TROUBLESHOOTING

ERROR: Cannot connect to Docker

Solution: Start Docker Desktop or Docker daemon

ERROR: Extension not found

Solution: Add extension to custom_extensions config

ERROR: Schema differences found

Solution: Review consolidation rules, adjust safety level, or fix migrations

# macOS - Start Docker
open -a Docker

# Linux - Start Docker daemon
sudo systemctl start docker

# Check Docker status
docker ps
// Add custom extensions
"custom_extensions": {
  "my_extension": "postgres:16"
}

NEXT STEPS

How is this guide?

On this page