Swellow π¦ββ¬

swellow is the simple, SQL-first tool for managing table migrations, written in Rust.
Built For Your Data Flock

Why Swellow?
If you can write SQL for your database, you already know how to use swellow.
Instead of offering a feature-rich migration DSL, swellow acts as a thin wrapper over your database engine. Migrations are defined as plain SQL files in a directory, and swellow tracks their execution using a small metadata table (swellow.records) in the target database.
There is:
- β No generated SQL;
- β No implicit transformations;
- β No migration logic hidden from the user;
β What runs is exactly what you wrote, using your databaseβs native syntax.
β This makes migrations transparent, predictable, and safe, because knowing what runs in production matters more than convenient abstractions.
If you want a migration tool that stays out of your way and treats SQL as the source of truth, swellow is for you.
Getting Started
swellow comes in many forms, the primary being the Python CLI and package. For the brave, you can try the Rust binary as well.
We've also created a GitHub Action for quick-and-easy integration in CI pipelines.
Behind the scenes, all versions of swellow use the same Rust backend, ensuring consistent behaviour across tools, so let's get started!
Just like with any other Python package:
And use it as a CLI:
Just like with any other Python package:
Now you can import it:
=
=
Simply add it to your workflow:
- name: Execute migrations
use: franciscoabsampaio/action-swellow@v1
with:
- command: peck
- connection-string: postgresql://<username>:<password>@<host>:<port>/<database>
It's that easy!
Go to the repository's latest release and download the binary, or do it in the terminal:
# We show for linux, but you can find binaries for other platforms as well.
|
Install it:
Verify the installation:
And ensure that swellow has everything it needs to run with peck:
Creating New Migrations
swellow lets you define migrations using plain SQL from your database of choice.
To create a new migration, the user must define a directory where all migration scripts will be housed.
New migrations are defined by a subdirectory in the migrations directory, that must contain an up.sql and a down.sql script, and must follow the following naming convention:
# Assuming the migrations directory is "./migrations"
Here's what an up.sql script may look like:
-- Create a table of birds π¦ββ¬
(
bird_id SERIAL PRIMARY KEY,
common_name TEXT NOT NULL,
latin_name TEXT NOT NULL,
wingspan_cm INTEGER,
dtm_hatched_at TIMESTAMP DEFAULT now,
dtm_last_seen_at TIMESTAMP DEFAULT now
);
-- Add a new column to track nest activity πͺΊ
nest ADD COLUMN twigs_collected INTEGER;
swellow automatically gathers all migrations within the specified range (by default, all that haven't been applied), and executes them.
up.sql scripts specify the new migration to be applied, and down.sql scripts their respective rollback scripts. Missing up.sql scripts and missing down.sql scripts will result in errors when migrating and rolling back, respectively.
If any migration or rollback fails, the transaction will be rolled back, and the database will keep its original state. Users can also preemptively check the validity of transactions by passing the --dry-run flag, which automatically cancels (and rolls back) the transaction after executing all migrations.
Pecking is Optional
swellow keeps track of migrations in its records table, which resides in a special schema swellow that it creates when the command peck is executed.
Behind the scenes, all migration commands start by running peck, making it, in most cases, superfluous. Pecking can be very useful for testing database connectivity, though. More importantly, perhaps, it really makes you feel like a bird.
Taking Snapshots
β οΈ swellow snapshot does not save any data. It is aimed at cleaning up directories filled with old migrations and combining them into a current definition of the database. The snapshot command/function scans the database and creates an up.sql script with everything needed to create all relations in the database.
In line with swellow's 'SQL-first' design philosophy, we believe that native options should be used when available (e.g. pg_dump for PostgreSQL). Unfortunately, this can make snapshotting behaviour very inconsistent across databases. On the upside, snapshots are completely harmless.
Here's a quick reference to what snapshotting does for each database:
- Postgres: runs
pg_dumpagainst the database. - Spark-Delta: iterates through all databases and tables, generating
CREATE DATABASEfor databases, and parsing table properties obtained fromDESCRIBE TABLEandDESCRIBE DETAILintoCREATEstatements. - Spark-Iceberg: iterates through all databases and tables, generating
CREATE DATABASEfor databases and executing Iceberg's nativeSHOW CREATE TABLEfor tables.
Users are encouraged to take a look at the source code, look up the relevant documentation, and if they find any limitation with the snapshotting behaviour, open an issue.
Migrating to Swellow
swellow makes as few assumptions as possible about an existing database, and prioritizes native options when available. For this reason, given a directory of migration scripts, all that is required is a connection to the existing database - swellow up will take care of the rest.
If you wish to start tracking the database in CI, take a snapshot.
If a swellow.records table already exists in the target database, the latest migration version in its active records (a record is active if it has a status of APPLIED or TESTED) will be assumed as the current version. This can easily be overriden by specifying the current_version argument, or changing the versions in migrations directory to be larger.
Examples
Refer to the examples directory in this repository for examples on how to use swellow with your data flock.
CLI Reference
swellow --help will show you all commands and options available.
)
Β© 2025 Francisco A. B. Sampaio. Licensed under the MIT License.
This project is not affiliated with, endorsed by, or sponsored by the Apache Software Foundation.