| Crates.io | schema-sync |
| lib.rs | schema-sync |
| version | 1.0.0 |
| created_at | 2026-01-01 14:42:20.930127+00 |
| updated_at | 2026-01-01 14:42:20.930127+00 |
| description | Production-grade schema synchronization for multi-tenant databases |
| homepage | |
| repository | https://github.com/exeebit/schema-sync |
| max_upload_size | |
| id | 2016287 |
| size | 100,338 |
Developer: s4gor
Github: https://github.com/s4gor
Production-grade schema synchronization for multi-tenant databases.
Schema Sync is designed to manage schema synchronization across multiple tenant schemas in a single database. It provides a robust, extensible foundation for detecting, analyzing, and managing schema differences safely.
This crate is designed extension-first. All core abstractions are trait-based, allowing:
┌─────────────────────────────────────────────────────────────┐
│ CLI Layer │
│ (dry-run, diff, validation, audit modes) │
└───────────────────────┬─────────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────────┐
│ Engine Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Planner │→ │ Executor │→ │ Diff │→ │ Snapshot │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└───────────────────────┬─────────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────────┐
│ Adapter Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Database │ │ Migration │ │ Schema │ │
│ │ Adapter │ │ Runner │ │ Inspector │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└───────────────────────┬─────────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────────┐
│ Database-Specific Implementations │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │PostgreSQL│ │ MySQL │ │ SQLite │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
The main entry point for database operations. Provides:
Why this abstraction exists: Allows different database types to be plugged in without changing core logic.
Read-only schema introspection. Produces normalized SchemaSnapshot objects.
Why this abstraction exists:
Executes schema changes. Supports different migration strategies.
Why this abstraction exists:
Creates executable migration plans from schema diffs.
Why this abstraction exists:
Orchestrates the execution of migration plans.
Why this abstraction exists:
Calculates differences between schema snapshots.
Why this abstraction exists:
Stores and retrieves schema snapshots.
Why this abstraction exists:
Preview schema changes without applying them. Output formats:
Implementation: Use Engine::sync_tenant() with execute=false.
Run in CI to ensure all tenants match expected schema. Exit non-zero if mismatch detected.
Implementation: Use Engine::sync_tenant() in dry-run mode for all tenants, check already_in_sync flag.
PostgreSQL (primary), MySQL, SQLite support through adapter implementations.
Implementation: Implement DatabaseAdapter, SchemaInspector, and MigrationRunner traits for each database type.
Detect drift without locks. Safe for production observability.
Implementation: Use SchemaInspector directly, no MigrationRunner needed.
Support SQL file migrations, Rust-based migrations, external tools (diesel, sqlx).
Implementation: Implement MigrationRunner trait with different strategies.
Store normalized schema snapshots. Allow diffing schema version A vs B.
Implementation: Use SnapshotStore trait implementations.
No cross-tenant leakage. Strict tenant scoping. Explicit locking strategy per tenant.
Implementation: All operations require TenantContext. MigrationRunner::acquire_lock() ensures isolation.
src/
├── lib.rs # Main library entry point
├── adapters.rs # Database adapter traits
├── diff.rs # Schema diff calculation
├── engine.rs # Main engine orchestration
├── errors.rs # Error types
├── planner.rs # Migration planning
├── executor.rs # Migration execution
├── snapshot.rs # Schema snapshots
└── cli.rs # CLI types and context
use schema_sync::prelude::*;
let adapter = PostgresAdapter::new("postgresql://...").await?;
let engine = Engine::from_adapter(/* ... */);
let tenant = TenantContext::new("tenant_123");
let result = engine.sync_tenant(&tenant, Some(&target_snapshot), true).await?;
let result = engine.sync_tenant(&tenant, Some(&target_snapshot), false).await?;
if !result.diff.is_empty() {
println!("Would apply {} changes", result.diff.change_count());
}
let tenants = engine.list_tenants().await?;
for tenant in tenants {
let result = engine.sync_tenant(&tenant, None, false).await?;
if !result.already_in_sync {
eprintln!("Schema mismatch for {}", tenant.id());
std::process::exit(1);
}
}
This is the foundation layer of schema-sync. It provides:
✅ Core trait definitions
✅ Data structures for schemas, diffs, and plans
✅ Architecture for extensibility
✅ Example usage patterns
🚧 Not yet implemented:
When implementing database adapters or other components:
MIT OR Apache-2.0