<div align="center">
<h1 align="center">Synq</h1>
<p align="center">
A modern, snapshot-based database migration tool for SQLAlchemy.
</p>
<p align="center">
<a href="https://pypi.org/project/synq-db/"><img alt="PyPI" src="https://img.shields.io/pypi/v/synq-db?color=blue"></a>
<a href="https://github.com/SudoAI-DEV/Synq/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/SudoAI-DEV/Synq/actions/workflows/ci.yml/badge.svg"></a>
<a href="https://github.com/SudoAI-DEV/Synq/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/synq-db"></a>
</p>
</div>
---
**Synq** brings the fast, offline-first workflow of tools like [Drizzle ORM](https://orm.drizzle.team/) to the Python and SQLAlchemy ecosystem. Instead of connecting to a database to detect schema changes (reflection), Synq uses schema snapshots to generate new migrations. This makes the process deterministic, incredibly fast, and independent of your database's state during development.
## Core Philosophy
Why choose Synq? It's all about the workflow.
| Feature | **Synq (Snapshot-based)** | **Traditional (Reflection-based e.g., Alembic)** |
| ----------------------- | ----------------------------------------------------------- | ------------------------------------------------------- |
| **Generation Source** | Compares your code (`MetaData`) to a **local snapshot file**. | Compares your code (`MetaData`) to a **live database**. |
| **DB Connection?** | **Not required** to generate migrations. | **Required** to generate migrations. |
| **Speed** | Extremely fast file-based comparison. | Slower, involves network latency and DB queries. |
| **Determinism** | 100% deterministic. The output only depends on your code. | Can be influenced by the state of the reference DB. |
| **Workflow** | Ideal for offline development and clean CI/CD pipelines. | Tightly coupled with a development database instance. |
## ✨ Key Features
* **Offline Migration Generation**: Create new SQL migration scripts without ever touching a database.
* **Snapshot-based Diffing**: Synq creates a `snapshot.json` file for each migration, representing the state of your schema at that point in time.
* **Pure SQL Migrations**: Generates plain, easy-to-read `.sql` files that you can inspect and even modify before applying.
* **Simple & Modern CLI**: A clean, intuitive command-line interface to manage your migration lifecycle.
* **SQLAlchemy Native**: Built on top of SQLAlchemy's powerful `MetaData` and dialect-specific DDL compilation.
## 🚀 Quick Start
#### 1. Installation
```bash
# Basic installation (includes SQLite support)
pip install synq-db
# With PostgreSQL support
pip install synq-db[postgres]
# With MySQL support
pip install synq-db[mysql]
# With all database drivers
pip install synq-db[postgres,mysql]
```
*(Note: The package name is `synq-db` to avoid conflicts, but the command is `synq`)*
#### 2. Initialize Synq
In your project root, run:
```bash
synq init
```
This will create a `migrations` directory and a `synq.toml` configuration file.
```
.
├── my_app/
│ └── models.py
├── migrations/
│ └── meta/
└── synq.toml
```
#### 3. Define Your Models
Synq supports both SQLAlchemy 1.4+ Table definitions and SQLAlchemy 2.0+ declarative models.
**SQLAlchemy 2.0+ (Recommended):**
```python
# my_app/models.py
from datetime import datetime
from typing import Optional
from sqlalchemy import String, DateTime, ForeignKey, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
metadata_obj = Base.metadata # Reference for Synq
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
username: Mapped[str] = mapped_column(String(50), unique=True)
email: Mapped[str] = mapped_column(String(100), unique=True)
created_at: Mapped[Optional[datetime]] = mapped_column(
DateTime, server_default=func.now()
)
posts: Mapped[list["Post"]] = relationship("Post", back_populates="author")
class Post(Base):
__tablename__ = "posts"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(200))
author_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
author: Mapped["User"] = relationship("User", back_populates="posts")
```
**SQLAlchemy 1.4+ (Legacy):**
```python
# my_app/models.py
from sqlalchemy import MetaData, Table, Column, Integer, String, ForeignKey
metadata_obj = MetaData()
users_table = Table(
"users", metadata_obj,
Column("id", Integer, primary_key=True),
Column("username", String(50), nullable=False, unique=True),
Column("email", String(100), nullable=False, unique=True),
)
posts_table = Table(
"posts", metadata_obj,
Column("id", Integer, primary_key=True),
Column("title", String(200), nullable=False),
Column("author_id", Integer, ForeignKey("users.id")),
)
```
#### 4. Configure Synq
Edit `synq.toml` to point to your `MetaData` object and your database URI.
```toml
# synq.toml
[synq]
# Path to your SQLAlchemy MetaData instance
metadata_path = "my_app.models:metadata_obj"
# Database connection string (used only for 'migrate')
db_uri = "postgresql://user:password@localhost/mydatabase"
```
#### 5. Generate Your First Migration
Synq can automatically generate intelligent migration names, or you can provide your own:
```bash
# Auto-generate name based on detected changes
synq generate
# Provide a custom description
synq generate "Create user and post tables"
# Use a specific name (overrides auto-generation)
synq generate --name "initial_schema"
```
Synq compares your code with an empty state and creates two new files:
```
migrations/
├── 0000_initial_migration.sql # The generated SQL
└── meta/
└── 0000_snapshot.json # The schema snapshot
```
**Example generated migration names:**
- `create_users_table` - Single table creation
- `add_email_to_users` - Single column addition
- `initial_migration` - Multiple table creation
- `update_schema` - Mixed operations across tables
#### 6. Apply the Migration
Run the migration against your database.
```bash
synq migrate -y
```
Synq connects to the database, checks which migrations haven't been applied, and runs the SQL script. Your database is now in sync with your models!
#### 7. Iterative Development
As you modify your models, Synq detects changes and generates new migrations:
```bash
# Add new models or modify existing ones in your code
# Then generate a new migration
synq generate # Automatically detects changes
# Apply the new migration
synq migrate -y
# Check status anytime
synq status
```
## CLI Command Reference
### `synq init`
Initializes the project structure with migration directories and configuration.
```bash
synq init --metadata-path "myapp.models:metadata_obj" --db-uri "postgresql://..."
```
### `synq generate`
Generates a new migration by comparing your current schema to the latest snapshot.
```bash
# Auto-generate name based on detected operations
synq generate
# Provide custom description
synq generate "Add user authentication"
# Use specific name (overrides auto-generation)
synq generate --name "v2_auth_system"
# Use custom config file
synq generate -c /path/to/synq.toml
```
### `synq migrate`
Applies all pending migrations to the database.
```bash
# Interactive mode (prompts for confirmation)
synq migrate
# Auto-confirm all migrations
synq migrate -y
# Dry run (show what would be applied)
synq migrate --dry-run
```
### `synq status`
Shows the current migration status and pending changes.
```bash
synq status
```
## Supported Databases
Synq supports all databases that SQLAlchemy supports:
- **SQLite** - Built-in support
- **PostgreSQL** - Install: `pip install synq-db[postgres]`
- **MySQL** - Install: `pip install synq-db[mysql]`
- **Oracle, SQL Server, etc.** - Use appropriate SQLAlchemy drivers
## Python & SQLAlchemy Support
- **Python**: 3.9, 3.10, 3.11, 3.12, 3.13
- **SQLAlchemy**: 1.4+ and 2.0+
- **Operating Systems**: Linux, macOS, Windows
## Migration Naming
Synq automatically generates intelligent migration names based on detected operations:
| Operations | Generated Name | Example |
|------------|----------------|---------|
| Single table creation | `create_{table}_table` | `create_users_table` |
| Multiple table creation | `initial_migration` | `initial_migration` |
| Single column addition | `add_{column}_to_{table}` | `add_email_to_users` |
| Multiple columns to one table | `add_columns_to_{table}` | `add_columns_to_users` |
| Mixed operations on one table | `update_{table}_schema` | `update_users_schema` |
| Mixed operations on multiple tables | `update_schema` | `update_schema` |
| Table deletion | `delete_{table}_table` | `delete_old_table` |
| Index creation | `add_{index}_to_{table}` | `add_email_index_to_users` |
You can always override auto-generated names with `--name` or by providing a description.
## 🤝 Contributing
Contributions are welcome! We are excited to see this project grow with the help of the community. Please see our `CONTRIBUTING.md` file for guidelines on how to get started.
## 📜 License
Synq is licensed under the **MIT License**. See the `LICENSE` file for more details.
## 🙏 Acknowledgments
* Heavily inspired by the fantastic workflow of **[Drizzle ORM](https://orm.drizzle.team/)**.
* Built on the powerful and robust foundation of **[SQLAlchemy](https://www.sqlalchemy.org/)**.
Raw data
{
"_id": null,
"home_page": null,
"name": "synq-db",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "database, migration, schema, snapshot, sqlalchemy",
"author": "Synq Contributors",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/46/3b/0dfe98edd780388e184ab7821b46b4e47d7178809920e0bb7ade87942662/synq_db-0.0.1.tar.gz",
"platform": null,
"description": "<div align=\"center\">\n <h1 align=\"center\">Synq</h1>\n <p align=\"center\">\n A modern, snapshot-based database migration tool for SQLAlchemy.\n </p>\n\n <p align=\"center\">\n <a href=\"https://pypi.org/project/synq-db/\"><img alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/synq-db?color=blue\"></a>\n <a href=\"https://github.com/SudoAI-DEV/Synq/actions/workflows/ci.yml\"><img alt=\"CI\" src=\"https://github.com/SudoAI-DEV/Synq/actions/workflows/ci.yml/badge.svg\"></a>\n <a href=\"https://github.com/SudoAI-DEV/Synq/blob/main/LICENSE\"><img alt=\"License\" src=\"https://img.shields.io/pypi/l/synq-db\"></a>\n </p>\n</div>\n\n---\n\n**Synq** brings the fast, offline-first workflow of tools like [Drizzle ORM](https://orm.drizzle.team/) to the Python and SQLAlchemy ecosystem. Instead of connecting to a database to detect schema changes (reflection), Synq uses schema snapshots to generate new migrations. This makes the process deterministic, incredibly fast, and independent of your database's state during development.\n\n## Core Philosophy\n\nWhy choose Synq? It's all about the workflow.\n\n| Feature | **Synq (Snapshot-based)** | **Traditional (Reflection-based e.g., Alembic)** |\n| ----------------------- | ----------------------------------------------------------- | ------------------------------------------------------- |\n| **Generation Source** | Compares your code (`MetaData`) to a **local snapshot file**. | Compares your code (`MetaData`) to a **live database**. |\n| **DB Connection?** | **Not required** to generate migrations. | **Required** to generate migrations. |\n| **Speed** | Extremely fast file-based comparison. | Slower, involves network latency and DB queries. |\n| **Determinism** | 100% deterministic. The output only depends on your code. | Can be influenced by the state of the reference DB. |\n| **Workflow** | Ideal for offline development and clean CI/CD pipelines. | Tightly coupled with a development database instance. |\n\n## \u2728 Key Features\n\n* **Offline Migration Generation**: Create new SQL migration scripts without ever touching a database.\n* **Snapshot-based Diffing**: Synq creates a `snapshot.json` file for each migration, representing the state of your schema at that point in time.\n* **Pure SQL Migrations**: Generates plain, easy-to-read `.sql` files that you can inspect and even modify before applying.\n* **Simple & Modern CLI**: A clean, intuitive command-line interface to manage your migration lifecycle.\n* **SQLAlchemy Native**: Built on top of SQLAlchemy's powerful `MetaData` and dialect-specific DDL compilation.\n\n## \ud83d\ude80 Quick Start\n\n#### 1. Installation\n\n```bash\n# Basic installation (includes SQLite support)\npip install synq-db\n\n# With PostgreSQL support\npip install synq-db[postgres]\n\n# With MySQL support \npip install synq-db[mysql]\n\n# With all database drivers\npip install synq-db[postgres,mysql]\n```\n*(Note: The package name is `synq-db` to avoid conflicts, but the command is `synq`)*\n\n#### 2. Initialize Synq\n\nIn your project root, run:\n\n```bash\nsynq init\n```\n\nThis will create a `migrations` directory and a `synq.toml` configuration file.\n\n```\n.\n\u251c\u2500\u2500 my_app/\n\u2502 \u2514\u2500\u2500 models.py\n\u251c\u2500\u2500 migrations/\n\u2502 \u2514\u2500\u2500 meta/\n\u2514\u2500\u2500 synq.toml\n```\n\n#### 3. Define Your Models\n\nSynq supports both SQLAlchemy 1.4+ Table definitions and SQLAlchemy 2.0+ declarative models.\n\n**SQLAlchemy 2.0+ (Recommended):**\n\n```python\n# my_app/models.py\nfrom datetime import datetime\nfrom typing import Optional\nfrom sqlalchemy import String, DateTime, ForeignKey, func\nfrom sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship\n\nclass Base(DeclarativeBase):\n pass\n\nmetadata_obj = Base.metadata # Reference for Synq\n\nclass User(Base):\n __tablename__ = \"users\"\n \n id: Mapped[int] = mapped_column(primary_key=True)\n username: Mapped[str] = mapped_column(String(50), unique=True)\n email: Mapped[str] = mapped_column(String(100), unique=True)\n created_at: Mapped[Optional[datetime]] = mapped_column(\n DateTime, server_default=func.now()\n )\n \n posts: Mapped[list[\"Post\"]] = relationship(\"Post\", back_populates=\"author\")\n\nclass Post(Base):\n __tablename__ = \"posts\"\n \n id: Mapped[int] = mapped_column(primary_key=True)\n title: Mapped[str] = mapped_column(String(200))\n author_id: Mapped[int] = mapped_column(ForeignKey(\"users.id\"))\n \n author: Mapped[\"User\"] = relationship(\"User\", back_populates=\"posts\")\n```\n\n**SQLAlchemy 1.4+ (Legacy):**\n\n```python\n# my_app/models.py\nfrom sqlalchemy import MetaData, Table, Column, Integer, String, ForeignKey\n\nmetadata_obj = MetaData()\n\nusers_table = Table(\n \"users\", metadata_obj,\n Column(\"id\", Integer, primary_key=True),\n Column(\"username\", String(50), nullable=False, unique=True),\n Column(\"email\", String(100), nullable=False, unique=True),\n)\n\nposts_table = Table(\n \"posts\", metadata_obj,\n Column(\"id\", Integer, primary_key=True),\n Column(\"title\", String(200), nullable=False),\n Column(\"author_id\", Integer, ForeignKey(\"users.id\")),\n)\n```\n\n#### 4. Configure Synq\n\nEdit `synq.toml` to point to your `MetaData` object and your database URI.\n\n```toml\n# synq.toml\n[synq]\n# Path to your SQLAlchemy MetaData instance\nmetadata_path = \"my_app.models:metadata_obj\"\n\n# Database connection string (used only for 'migrate')\ndb_uri = \"postgresql://user:password@localhost/mydatabase\"\n```\n\n#### 5. Generate Your First Migration\n\nSynq can automatically generate intelligent migration names, or you can provide your own:\n\n```bash\n# Auto-generate name based on detected changes\nsynq generate\n\n# Provide a custom description \nsynq generate \"Create user and post tables\"\n\n# Use a specific name (overrides auto-generation)\nsynq generate --name \"initial_schema\"\n```\n\nSynq compares your code with an empty state and creates two new files:\n\n```\nmigrations/\n\u251c\u2500\u2500 0000_initial_migration.sql # The generated SQL\n\u2514\u2500\u2500 meta/\n \u2514\u2500\u2500 0000_snapshot.json # The schema snapshot\n```\n\n**Example generated migration names:**\n- `create_users_table` - Single table creation\n- `add_email_to_users` - Single column addition \n- `initial_migration` - Multiple table creation\n- `update_schema` - Mixed operations across tables\n\n#### 6. Apply the Migration\n\nRun the migration against your database.\n\n```bash\nsynq migrate -y\n```\n\nSynq connects to the database, checks which migrations haven't been applied, and runs the SQL script. Your database is now in sync with your models!\n\n#### 7. Iterative Development\n\nAs you modify your models, Synq detects changes and generates new migrations:\n\n```bash\n# Add new models or modify existing ones in your code\n# Then generate a new migration\nsynq generate # Automatically detects changes\n\n# Apply the new migration\nsynq migrate -y\n\n# Check status anytime\nsynq status\n```\n\n## CLI Command Reference\n\n### `synq init`\nInitializes the project structure with migration directories and configuration.\n\n```bash\nsynq init --metadata-path \"myapp.models:metadata_obj\" --db-uri \"postgresql://...\"\n```\n\n### `synq generate`\nGenerates a new migration by comparing your current schema to the latest snapshot.\n\n```bash\n# Auto-generate name based on detected operations\nsynq generate\n\n# Provide custom description\nsynq generate \"Add user authentication\"\n\n# Use specific name (overrides auto-generation) \nsynq generate --name \"v2_auth_system\"\n\n# Use custom config file\nsynq generate -c /path/to/synq.toml\n```\n\n### `synq migrate`\nApplies all pending migrations to the database.\n\n```bash\n# Interactive mode (prompts for confirmation)\nsynq migrate\n\n# Auto-confirm all migrations\nsynq migrate -y\n\n# Dry run (show what would be applied)\nsynq migrate --dry-run\n```\n\n### `synq status`\nShows the current migration status and pending changes.\n\n```bash\nsynq status\n```\n\n## Supported Databases\n\nSynq supports all databases that SQLAlchemy supports:\n\n- **SQLite** - Built-in support\n- **PostgreSQL** - Install: `pip install synq-db[postgres]`\n- **MySQL** - Install: `pip install synq-db[mysql]`\n- **Oracle, SQL Server, etc.** - Use appropriate SQLAlchemy drivers\n\n## Python & SQLAlchemy Support\n\n- **Python**: 3.9, 3.10, 3.11, 3.12, 3.13\n- **SQLAlchemy**: 1.4+ and 2.0+\n- **Operating Systems**: Linux, macOS, Windows\n\n## Migration Naming\n\nSynq automatically generates intelligent migration names based on detected operations:\n\n| Operations | Generated Name | Example |\n|------------|----------------|---------|\n| Single table creation | `create_{table}_table` | `create_users_table` |\n| Multiple table creation | `initial_migration` | `initial_migration` |\n| Single column addition | `add_{column}_to_{table}` | `add_email_to_users` |\n| Multiple columns to one table | `add_columns_to_{table}` | `add_columns_to_users` |\n| Mixed operations on one table | `update_{table}_schema` | `update_users_schema` |\n| Mixed operations on multiple tables | `update_schema` | `update_schema` |\n| Table deletion | `delete_{table}_table` | `delete_old_table` |\n| Index creation | `add_{index}_to_{table}` | `add_email_index_to_users` |\n\nYou can always override auto-generated names with `--name` or by providing a description.\n\n## \ud83e\udd1d Contributing\n\nContributions are welcome! We are excited to see this project grow with the help of the community. Please see our `CONTRIBUTING.md` file for guidelines on how to get started.\n\n## \ud83d\udcdc License\n\nSynq is licensed under the **MIT License**. See the `LICENSE` file for more details.\n\n## \ud83d\ude4f Acknowledgments\n\n* Heavily inspired by the fantastic workflow of **[Drizzle ORM](https://orm.drizzle.team/)**.\n* Built on the powerful and robust foundation of **[SQLAlchemy](https://www.sqlalchemy.org/)**.\n",
"bugtrack_url": null,
"license": null,
"summary": "A modern, snapshot-based database migration tool for SQLAlchemy",
"version": "0.0.1",
"project_urls": {
"Changelog": "https://github.com/SudoAI-DEV/Synq/blob/main/CHANGELOG.md",
"Documentation": "https://github.com/SudoAI-DEV/Synq#readme",
"Repository": "https://github.com/SudoAI-DEV/Synq"
},
"split_keywords": [
"database",
" migration",
" schema",
" snapshot",
" sqlalchemy"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "b0b44c0e6a595bf452a5405e58297cdb4fc8b3f2e942643f9733fe26d8a15d46",
"md5": "d7e32618273256a2fe2b58c1c56b7fcc",
"sha256": "3ed4282e7fd70b3312f05494a77b7921d012fdb0c6f135f6c3aa8b90388d584d"
},
"downloads": -1,
"filename": "synq_db-0.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "d7e32618273256a2fe2b58c1c56b7fcc",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 28640,
"upload_time": "2025-08-04T11:18:44",
"upload_time_iso_8601": "2025-08-04T11:18:44.018418Z",
"url": "https://files.pythonhosted.org/packages/b0/b4/4c0e6a595bf452a5405e58297cdb4fc8b3f2e942643f9733fe26d8a15d46/synq_db-0.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "463b0dfe98edd780388e184ab7821b46b4e47d7178809920e0bb7ade87942662",
"md5": "8e9c53083c309fe1e77e6658af9bec9a",
"sha256": "56d477ef88ddd869e55bbe7c0e85fbccb7dbe1dd7e1cd204e7e8e7af72dac3db"
},
"downloads": -1,
"filename": "synq_db-0.0.1.tar.gz",
"has_sig": false,
"md5_digest": "8e9c53083c309fe1e77e6658af9bec9a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 74902,
"upload_time": "2025-08-04T11:18:45",
"upload_time_iso_8601": "2025-08-04T11:18:45.325062Z",
"url": "https://files.pythonhosted.org/packages/46/3b/0dfe98edd780388e184ab7821b46b4e47d7178809920e0bb7ade87942662/synq_db-0.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-04 11:18:45",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "SudoAI-DEV",
"github_project": "Synq",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "synq-db"
}