A fast, deterministic, Rust-native ODBC schema migration tool.
Run versioned SQL migrations against ODBC-only databases with safety, auditability, and zero JVM overhead.
Most enterprise data platforms (e.g. Databricks, Snowflake, Synapse) expose ODBC-only interfaces, yet migration tooling is dominated by JDBC-based Java tools like Flyway and Liquibase.
deriDDL eliminates the bloat:
- No JVM
- No XML/DSL
- No per-connection licensing
- Just SQL + Rust
🆚 deriDDL vs Flyway vs Liquibase (2025)
| Feature | deriDDL | Flyway | Liquibase |
|---|---|---|---|
| Core Features | |||
Versioned migrations (V###.sql) |
✅ Native SQL | ✅ V__*.sql | ✅ ChangeSets |
| Migration history table | ✅ schema_migrations |
✅ flyway_schema_history |
✅ DATABASECHANGELOG |
| Filename, checksum, execution time | ✅ Logged | ✅ Logged | ✅ Logged |
| Idempotent execution | ✅ Via history tracking | ✅ Enforced via history | ✅ Enforced via history |
| Migration Types | |||
| Repeatable migrations | ✅ R__*.sql | ✅ R__*.sql | ✅ runAlways="true" |
| Baseline support | ✅ baseline command |
✅ Baseline version | ✅ Baseline capability |
| Undo migrations | ❌ Not planned | ✅ U__*.sql (Teams) | ✅ Rollback (Pro) |
| Validation & Safety | |||
| Checksum drift validation | ✅ Present | ✅ Present | ✅ Enhanced v9 checksums |
| Dry-run execution | ✅ --dry-run flag |
✅ -dryRunOutput |
✅ update-sql command |
| SQL validation | ✅ SQLGlot integration | ||
| Migration assertion validation | ✅ Custom logic support | ❌ Not supported | ✅ Preconditions |
| Advanced Features | |||
| Callback hooks (lifecycle events) | ✅ Lifecycle callbacks | ✅ Flow conditionals | |
| Schema state tracking | ❌ Limited | ✅ Comprehensive | |
| Target schema support | ✅ Multi-schema aware | ✅ Multi-schema aware | |
| Migration labels/groups | ✅ Teams feature | ✅ Labels & contexts | |
| Out-of-order migration control | ✅ Optional | ✅ Optional | |
| Technology & Deployment | |||
| Runtime dependencies | ✅ Zero (static binary) | ❌ JVM required | ❌ JVM required |
| Configuration format | ✅ TOML | ✅ Properties/TOML | ✅ Properties/YAML |
| Database support | ✅ 20+ databases | ✅ 30+ databases | |
| Licensing & Cost | |||
| Open source core | ✅ MIT licensed | ✅ Apache 2.0 | ✅ Apache 2.0 |
| Enterprise features | ✅ All features free | ❌ Teams subscription | ❌ Pro subscription |
| Per-connection licensing | ✅ No restrictions |
✨ deriDDL Advantages:
- Zero Runtime Dependencies: Single static binary, no JVM overhead
- ODBC-First Design: Built specifically for ODBC-only databases
- Cost-Effective: All features free, no per-connection licensing
- Advanced SQL Validation: SQLGlot integration for comprehensive validation
- Rust Performance: Memory-safe, fast execution
⚖️ Trade-offs:
- Smaller Ecosystem: Newer tool with growing community
- Database Coverage: ODBC-compatible databases only
- Enterprise Features: Some advanced features still in development
- ✅ ODBC-based execution via
odbc-api - ✅ Versioned
.sqlfile migrations - ✅ Repeatable migrations (
R__*.sql) - ✅
schema_migrationstracking table - ✅ Baseline support for existing databases
- ✅ Migration validation and integrity checking
- ✅ Dry-run mode for CI/CD verification
- ✅ TOML configuration system with environment support
- ✅ SQLGlot integration for SQL validation
- ✅ Health checks and system readiness verification
- ✅ Modular architecture for extension
- ✅ Single static binary (no runtime deps)
deriDDL supports flexible TOML-based configuration with environment-specific overrides.
Generate a default configuration file:
cargo run -- configThis creates config.toml with all available settings and sensible defaults.
[database]
# Connection string (can be overridden with --conn)
connection_string = "Driver={PostgreSQL};Server=localhost;..."
timeout = 30
max_retries = 3
[migrations]
path = "./migrations" # Directory containing .sql files
dialect = "postgres" # SQL dialect for validation
validate_sql = true # Enable SQLGlot validation
file_pattern = '^\d{4}_.*\.sql$' # Migration file naming pattern
[logging]
level = "info" # error, warn, info, debug, trace
colored = true
format = "pretty" # compact, pretty, json
[behavior]
auto_create_migrations_dir = false
require_confirmation = true
default_dry_run = false
[validation]
enable_sqlglot = true # Requires: pip install sqlglot
strict_validation = false # Fail on warnings, not just errors
max_file_size_mb = 10
[baseline]
default_description = "Database baseline"
auto_generate_schema = false # Generate schema dump on baseline
require_confirmation = true # Require confirmation before baseline
allow_on_existing_migrations = falseCreate environment overrides using the --env flag:
# Generate environment-specific config
cargo run -- config --env dev
cargo run -- config --env staging
cargo run -- config --env prodThis creates config/{env}.toml files that override the base configuration.
Example config/dev.toml:
[database]
connection_string = "Driver={PostgreSQL};Server=dev-db;..."
[migrations]
dialect = "postgres"
[logging]
level = "debug"- Base config:
config.tomlorconfig/default.toml - Environment override:
config/{env}.toml(if--envspecified) - Local overrides:
config/local.toml(git-ignored, always applied last) - CLI flags: Override everything
# Use default config
cargo run -- health
# Use specific environment
cargo run -- --env dev health
# Use custom config file
cargo run -- --config my-config.toml status
# CLI flags override everything
cargo run -- --env prod --conn "Driver=..." applymigrations/
├── 0001_init_schema.sql # Versioned migration
├── 0002_add_users_table.sql # Versioned migration
├── 0003_add_index.sql # Versioned migration
├── R__create_views.sql # Repeatable migration
└── R__refresh_statistics.sql # Repeatable migration
Files must follow the {version}_{description}.sql pattern where:
- Version: 4-digit zero-padded number (0001, 0002, etc.)
- Description: Snake_case description
- Extension:
.sql
Files must follow the R__{description}.sql pattern where:
- Prefix:
R__(capital R, double underscore) - Description: Snake_case description
- Extension:
.sql - Behavior: Re-run when file content (checksum) changes
Baseline support allows you to start using deriDDL on existing databases without having to create migration files for all existing schema objects.
- Legacy Database Migration: You have an existing production database and want to start using deriDDL
- Environment Promotion: Development uses migrations, but production was created from backups
- Schema Inheritance: Multiple databases with similar existing schema need consistent migration starting points
- Set Baseline: Tell deriDDL that your database is already at version X
- Skip Historical Migrations: Any migration ≤ baseline version is automatically skipped
- Apply Future Migrations: Only migrations > baseline version are applied
# Create baseline at version 100 (dry-run first)
cargo run -- baseline --conn "DSN=prod_db;" --version 100 --description "Production v2.1 state" --dry-run
# Create baseline and generate schema dump
cargo run -- baseline --conn "DSN=prod_db;" --version 100 --description "Production v2.1 state" --from-schema
# Using configuration defaults
cargo run -- --env prod baseline --version 100 --description "Prod baseline"[baseline]
default_description = "Database baseline" # Default description
auto_generate_schema = false # Auto-generate schema dump
require_confirmation = true # Require confirmation
allow_on_existing_migrations = false # Allow baseline with existing migrationsVerify system readiness and dependencies:
# Check with default settings
cargo run -- health
# Check specific environment
cargo run -- --env prod health
# Check with custom path and dialect
cargo run -- health --path ./my-migrations --dialect mysqlHealth checks include:
- ✅ Python installation
- ✅ SQLGlot availability and dialect support
- ✅ Migrations directory accessibility
- ✅ File permissions
- ✅ Migration sequence validation
# Generate default config
cargo run -- config
# Generate environment-specific configs
cargo run -- config --env dev
cargo run -- config --env staging
cargo run -- config --env prod
# Custom output location
cargo run -- config --output my-config.toml# Initialize schema_migrations table
cargo run -- init --conn "Driver={PostgreSQL};..."
# Check migration status
cargo run -- status --conn "..." --path ./migrations
# Preview pending migrations
cargo run -- plan --conn "..." --path ./migrations
# Validate migration integrity
cargo run -- validate --conn "..." --path ./migrations
# Create baseline for existing database
cargo run -- baseline --conn "..." --version 100 --description "Production v2.1 state" --dry-run
cargo run -- baseline --conn "..." --version 100 --description "Production v2.1 state" --from-schema
# Apply migrations (dry-run)
cargo run -- apply --conn "..." --path ./migrations --dry-run
# Apply migrations (live)
cargo run -- apply --conn "..." --path ./migrations# Validate migration integrity and checksums
cargo run -- validate --conn "..." --path ./migrations
# Validate with specific environment
cargo run -- --env prod validateValidation checks include:
- ✅ Checksum integrity (detect modified applied migrations)
- ✅ Orphaned database migrations (migrations in DB but not in files)
- ✅ Migration sequence consistency
- ✅ File accessibility and permissions
- ✅ Database connectivity
All commands support these global configuration flags:
--config <path>: Custom configuration file--env <environment>: Load environment-specific config
- Rust 2024 edition
- Python 3.x (for SQLGlot validation)
- Virtual environment with
sqlglotinstalled
# Clone and build
git clone <repo>
cd deriDDL
cargo build
# Set up Python environment (optional, for SQL validation)
python -m venv venv
source venv/bin/activate # or `venv\Scripts\activate` on Windows
pip install sqlglot
# Run health check
cargo run -- healthsrc/
├── cli/ # Command-line interface and argument parsing
├── model/ # Data structures (Migration, Config)
├── orchestrator/ # Business logic (apply, plan, status, health)
├── executor/ # ODBC connection and query execution
└── tracker/ # Migration state tracking
This project is licensed under the MIT License - see the LICENSE file for details.
We welcome contributions! Please follow these guidelines:
- Use the GitHub issue tracker
- Include system information (OS, Rust version, database type)
- Provide minimal reproduction steps
- Include relevant logs with
RUST_LOG=debug
# Fork and clone the repository
git clone https://github.com/yourusername/deriDDL.git
cd deriDDL
# Install dependencies
cargo check
# Set up pre-commit validation (optional)
python -m venv venv
source venv/bin/activate
pip install sqlglot
# Run tests and health checks
cargo test
cargo run -- health- Fork the repository and create a feature branch
- Write tests for new functionality
- Run the full test suite:
cargo test && cargo clippy && cargo fmt - Update documentation if needed
- Create a clear PR description explaining the changes
- Ensure CI passes before requesting review
- Follow
cargo fmtformatting - Pass
cargo clippywithout warnings - Use meaningful commit messages
- Add documentation for public APIs
- Include examples for new features
# Run unit tests
cargo test
# Run integration tests (requires database)
cargo test --features integration
# Test configuration system
cargo run -- config --env test
cargo run -- --env test health- Open an issue with the
enhancementlabel - Describe the use case and expected behavior
- Consider implementation complexity and maintenance burden
- Discuss design before starting large features
- Report security vulnerabilities privately via GitHub Security tab
- Do not commit secrets, API keys, or connection strings
- Follow secure coding practices for database operations
- Be respectful and inclusive
- Focus on constructive feedback
- Help newcomers get started
- Maintain a professional tone in all interactions