Skip to content

Architecture

Schemage separates schema description, database-specific interpretation, planning, SQL compilation, and execution.

Main flow

Schema DSL
    ↓
Desired Schema Metadata
    ↓
Database Introspection
    ↓
Current Schema Metadata
    ↓
Diff Engine
    ↓
Logical Operations
    ↓
Driver Operation Planner
    ↓
Operation Sorter
    ↓
SQL Generator
    ↓
Driver Grammar
    ↓
Migrator

Main components

Component Responsibility
DSL User-facing schema definition API
Metadata In-memory representation of tables, columns, indexes, checks, and foreign keys
Introspector Reads a database and converts driver-specific details into normalized metadata
Comparator Compares normalized metadata objects
SchemaDiffer Produces logical operations required to reach the desired schema
OperationPlanner Converts logical operations into operations supported by a driver
OperationSorter Orders executable operations safely and deterministically
Grammar Compiles a single operation into driver-specific SQL
SQLGenerator Normalizes grammar output into a flat list of SQL statements
Migrator Executes SQL and records migration history

Driver-specific planning

Most MySQL and MariaDB operations can be represented directly as ALTER TABLE statements.

SQLite has stricter alteration rules. Operations such as modifying a column or changing a foreign key are planned as a RecreateTable operation. The SQLite grammar then creates a temporary table, copies compatible data, replaces the original table, and recreates secondary indexes.

Design principles

  • The schema file is the source of truth.
  • Renames are explicit; they are never guessed automatically.
  • Introspectors normalize driver-specific representations.
  • Comparators remain mostly database-agnostic.
  • Planners decide how a logical change can be executed by a driver.
  • Grammars compile operations; they do not decide migration strategy.
  • Potential data loss requires stronger confirmation.