{"id":44068842,"url":"https://github.com/wack/tern","last_synced_at":"2026-02-08T04:03:37.797Z","repository":{"id":334099498,"uuid":"1137740257","full_name":"wack/tern","owner":"wack","description":"Language-agnostic database migrations compiled into reusable, self-documenting executables.","archived":false,"fork":false,"pushed_at":"2026-01-30T16:02:39.000Z","size":1058,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"trunk","last_synced_at":"2026-01-30T17:34:06.611Z","etag":null,"topics":["breaking-changes","database-migration","database-schema","developer-tools","devops","postgresql","schema-diff","schema-migration"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-19T19:14:32.000Z","updated_at":"2026-01-30T16:02:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/wack/tern","commit_stats":null,"previous_names":["wack/tern"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/wack/tern","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wack%2Ftern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wack%2Ftern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wack%2Ftern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wack%2Ftern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wack","download_url":"https://codeload.github.com/wack/tern/tar.gz/refs/heads/trunk","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wack%2Ftern/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29219379,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T03:18:47.732Z","status":"ssl_error","status_checked_at":"2026-02-08T03:15:31.985Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["breaking-changes","database-migration","database-schema","developer-tools","devops","postgresql","schema-diff","schema-migration"],"created_at":"2026-02-08T04:03:30.308Z","updated_at":"2026-02-08T04:03:37.787Z","avatar_url":"https://github.com/wack.png","language":"Rust","readme":"\u003cimg width=\"1584\" height=\"396\" alt=\"Tern: Migrations that outlive your application code\" src=\"https://github.com/user-attachments/assets/64168931-e51a-45e7-8628-cd34ff9e5cc8\" /\u003e\n\n\n# Tern\n\n[![CI](https://github.com/wack/tern/actions/workflows/on-push.yml/badge.svg)](https://github.com/wack/tern/actions/workflows/on-push.yml)\n[![Rust](https://img.shields.io/badge/rust-2024_edition-orange.svg)](https://www.rust-lang.org)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n**A database migration tool that compiles schema changes into standalone, self-documenting executables.**\n\nNamed after the Arctic tern—a bird that makes the longest migration of any species—Tern helps you navigate the journey from one database schema to another with confidence.\n\n## Table of Contents\n\n- [Key Features](#key-features)\n- [Quick Start](#quick-start)\n- [Installation](#installation)\n- [Commands](#commands)\n- [Concepts](#concepts)\n  - [State Backend](#state-backend)\n  - [Breaking Change Detection](#breaking-change-detection)\n  - [Migration Executables](#migration-executables)\n- [Architecture](#architecture)\n- [Contributing](#contributing)\n- [Supported Schema Objects](#supported-schema-objects)\n- [Roadmap](#roadmap)\n- [License](#license)\n\n## Key Features\n\n- **Schema introspection** — Automatically captures your PostgreSQL schema structure\n- **Intelligent diffing** — Detects additions, removals, modifications, and potential renames\n- **Breaking change detection** — Identifies risky changes and suggests mitigation strategies\n- **Standalone executables** — Compiles migrations to self-contained binaries via WebAssembly\n- **State tracking** — Maintains migration history locally without polluting your database\n- **Verification** — Detects schema drift between your state backend and live database\n\n## Quick Start\n\n```bash\n# Initialize a new project (captures current schema as baseline)\ntern init --from postgres://localhost/mydb\n\n# Make changes to your database schema, then compile a migration\ntern compile --database-url postgres://localhost/mydb --description \"Add users table\"\n\n# View migration history\ntern history\n\n# Verify state backend matches the database\ntern verify --database-url postgres://localhost/mydb\n```\n\n## Installation\n\n### From Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/wack/tern.git\ncd tern\n\n# Build release binary\ncargo build --release\n\n# The binary is at ./target/release/tern\n```\n\n### Prerequisites\n\n- Rust toolchain (stable, edition 2024)\n- PostgreSQL database\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `init` | Initialize a new Tern project with state backend |\n| `status` | Show state backend status and schema summary |\n| `compile` | Generate migration source code from schema diff |\n| `history` | List migration history |\n| `show` | Show details of a specific migration |\n| `record` | Record a migration as applied without executing |\n| `inspect` | Examine migration files (JSON or Rust source) |\n| `verify` | Check if state backend matches live database |\n| `verify-chain` | Validate migration chain integrity |\n| `print-migrations` | Print SQL to recreate current schema from scratch |\n\n### Examples\n\n```bash\n# Initialize from existing database\ntern init --from postgres://user:pass@localhost/mydb\n\n# Initialize with empty schema\ntern init\n\n# Compile migration with SQL preview\ntern compile \\\n  --database-url postgres://localhost/mydb \\\n  --description \"Add email column to users\" \\\n  --show-sql\n\n# Compile and record to state backend\ntern compile \\\n  --database-url postgres://localhost/mydb \\\n  --description \"Add indexes\" \\\n  --record\n\n# Preview changes without writing files\ntern compile \\\n  --database-url postgres://localhost/mydb \\\n  --description \"Preview\" \\\n  --dry-run\n\n# Show migration details as SQL\ntern show abc123 --format sql\n\n# Output in JSON for scripting\ntern status --format json\ntern history --format json\n```\n\n## Concepts\n\n### State Backend\n\nTern tracks migration history in a local `.tern/` directory:\n\n```\n.tern/\n├── state.json           # Current schema state\n└── migrations/\n    ├── index.json       # Ordered list of migration IDs\n    ├── 00001.json       # Baseline migration\n    ├── 00002.json       # Second migration\n    └── ...\n```\n\nEach migration is content-addressed using BLAKE3 hashes, ensuring tamper-resistant history and deterministic IDs.\n\n### Breaking Change Detection\n\nTern analyzes schema changes and classifies them by the mitigation strategy required:\n\n| Strategy | When Used | Examples |\n|----------|-----------|----------|\n| **Safe** | No special handling needed | Add nullable column, create table |\n| **Dual Write** | Requires parallel structures | Rename column, change column type |\n| **Backfill** | Requires populating data | Add NOT NULL to existing column |\n| **Ratchet** | Requires NOT VALID + VALIDATE pattern | Add unique/check/foreign key constraint |\n| **Destructive** | Intentionally removes data | Drop table, drop column |\n\nWhen compiling a migration with breaking changes, Tern warns you and documents the required mitigation.\n\n### Migration Executables\n\nTern compiles migrations to standalone executables using WebAssembly:\n\n```bash\n# The compiled migration is self-documenting\n./migration-add-users --describe\n\n# Preview SQL without executing\n./migration-add-users --database-url postgres://localhost/mydb --dry-run\n\n# Run the migration\n./migration-add-users --database-url postgres://localhost/mydb\n\n# Skip confirmation prompts for breaking changes\n./migration-add-users --database-url postgres://localhost/mydb --yes\n```\n\n## Architecture\n\nTern follows a **sans-I/O** design pattern, separating database access from business logic:\n\n```\nsrc/\n├── cli/           # Command-line interface (clap)\n└── db/\n    ├── model/     # In-memory PostgreSQL schema representation\n    ├── query/     # Database introspection (Catalog trait)\n    ├── diff/      # Schema comparison and rename detection\n    ├── migrate/   # Migration planning and SQL rendering\n    ├── compile/   # WebAssembly component generation\n    └── state/     # Migration history tracking\n```\n\nThe `Catalog` trait abstracts database queries, enabling comprehensive unit testing without a live database.\n\n## Contributing\n\nWe welcome GitHub issues and pull requests.\n\nBefore implementing a new feature or significant change, please open an issue to discuss it with a maintainer. This helps ensure your contribution aligns with the project's direction and avoids duplicate effort.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.\n\n## Supported Schema Objects\n\nTern captures and diffs the following PostgreSQL objects:\n\n- Tables with columns, defaults, identity columns, and generated columns\n- Primary keys, foreign keys, unique constraints, check constraints, exclusion constraints\n- Indexes with expressions, sort order, nulls handling, and partial predicates\n- Views (definition tracking)\n- Sequences\n- Enum types\n\n## Roadmap\n\nFuture enhancements under consideration:\n\n- Table partitioning support\n- Functions and procedures\n- Triggers\n- Row-level security policies\n- Domain and composite types\n- PostgreSQL state backend (store migrations in the database)\n- Multi-database support beyond PostgreSQL\n\n## License\n\nSee [LICENSE](LICENSE) for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwack%2Ftern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwack%2Ftern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwack%2Ftern/lists"}