{"id":13536854,"url":"https://github.com/emilpriver/geni","last_synced_at":"2026-04-29T00:11:06.171Z","repository":{"id":211986137,"uuid":"730433571","full_name":"emilpriver/geni","owner":"emilpriver","description":"Standalone database migration tool which works for Postgres, MariaDB, MySQL, Sqlite and LibSQL(Turso).","archived":false,"fork":false,"pushed_at":"2026-04-23T05:00:18.000Z","size":626,"stargazers_count":267,"open_issues_count":1,"forks_count":8,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-04-23T07:04:48.557Z","etag":null,"topics":["database-migrations","libsql","mariadb","mysql","postgres","rust","sqlite"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/emilpriver.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":"FUNDING.YML","license":"LICENSE","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},"funding":{"github":"emilpriver"}},"created_at":"2023-12-11T23:12:04.000Z","updated_at":"2026-04-23T05:00:15.000Z","dependencies_parsed_at":"2023-12-31T14:30:11.246Z","dependency_job_id":"583a52d4-f52a-4f83-a3bb-e0ef6f23012d","html_url":"https://github.com/emilpriver/geni","commit_stats":null,"previous_names":["emilpriver/libsql-migrate","emilpriver/geni"],"tags_count":42,"template":false,"template_full_name":null,"purl":"pkg:github/emilpriver/geni","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilpriver%2Fgeni","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilpriver%2Fgeni/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilpriver%2Fgeni/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilpriver%2Fgeni/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emilpriver","download_url":"https://codeload.github.com/emilpriver/geni/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilpriver%2Fgeni/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32402673,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T19:38:08.556Z","status":"ssl_error","status_checked_at":"2026-04-28T19:37:55.688Z","response_time":56,"last_error":"SSL_read: 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":["database-migrations","libsql","mariadb","mysql","postgres","rust","sqlite"],"created_at":"2024-08-01T09:00:50.619Z","updated_at":"2026-04-29T00:11:06.165Z","avatar_url":"https://github.com/emilpriver.png","language":"Rust","funding_links":["https://github.com/sponsors/emilpriver"],"categories":["Rust","Tools"],"sub_categories":["Community"],"readme":"# Geni\nGeni is a standalone migration tool designed to work in conjunction with your preferred ORM/toolkit/code. It allows multiple developers to collaborate without overriding database migrations. It can be used in a CD pipeline alongside your code to ensure your database stays up to date.\n\nThis project was heavily inspired by [dbmate](https://github.com/amacneil/dbmate) and was created because dbmate lacked support for LibSQL.\n\nThe application is developed using the Rust programming language and relies on the [libsql-client-rs](https://github.com/libsql/libsql-client-rs) library for SQLite and LibSQL. Moreover, it makes use of [SQLX](https://github.com/launchbadge/sqlx) to support Postgres, MariaDB, and MySQL databases. As this is written in rust is lighting fast, blazingly fast, tiny, ultra fast and memory safe\n\n## Geni in the news\n- [Database Migrations made easy with Geni by Jamie Barton](https://www.youtube.com/watch?v=EHVBqHF34hI)\n\n## Features\n\n- Databases:\n    - Postgres\n    - MariaDB\n    - MySQL\n    - SQLite\n    - LibSQL\n- Generating migrations using `geni new **name**`\n- Migrating using `geni up`\n- Rollback using `geni down`\n- Create database using  `geni create`\n- Dropping database using  `geni drop`\n- Timestamp based migrations\n- Running migrations in a transaction\n- Status command to see which migrations that is pending to be applied \n- Dump a schema.sql after each migration which can be used in version control\n  - Dumping needs another binaries to work:\n    - Postgres: Works without need for another binary. Uses SQL code to get schema\n    - MySQL: `mysqldump` need to be installed(already installed in docker)\n    - MariaDB: `mariadb-dump` need to be installed(already installed in docker)\n    - Sqlite: Works without need for another binary. Uses SQL code to get schema\n    - LibSQL: Works without need for another binary. Uses SQL code to get schema\n\n## TODO\n\n- [ ]  Databases\n    - [ ]  ClickHouse\n\n## Installation\n\n### Github\n\n```bash\n$ sudo curl -fsSL -o /usr/local/bin/geni https://github.com/emilpriver/geni/releases/latest/download/geni-linux-amd64\n$ sudo chmod +x /usr/local/bin/geni\n```\n\n### Homebrew\n\n```bash\nbrew install geni\n```\n\n### Scoop\n\nTBA\n\n### PKGX\nRun using PKGX\n```bash\npkgx geni up\n```\n\n### Nix flake\nRun using nix\n```bash\nnix run github:emilpriver/geni -- up\n```\n\n\n### Cargo\n\n```bash\ncargo install geni\n```\n\n### Docker\n\nDocker images are published to GitHub Container Registry ([ghcr.io/emilpriver/geni](https://ghcr.io/emilpriver/geni)).\n\n```bash\n$ docker run --rm -it --network=host ghcr.io/emilpriver/geni:latest --help\n```\nthere is also a slim docker image that don't have each database respective libraries(such as pg_dump). \n\nNote: *This image won't try to dump the database*\n\n```bash\n$ docker run --rm -it --network=host ghcr.io/emilpriver/geni:latest-slim --help\n```\n\nIf you wish to create or apply migrations, you will need to use Docker's [bind mount](https://docs.docker.com/storage/bind-mounts/) feature to make your local working directory (`pwd`) available inside the geni container:\n\n```bash\n$ docker run --rm -it --network=host -v \"$(pwd)/migrations:/migrations\" ghcr.io/emilpriver/geni:latest new create_users_table`\n```\n\n### Commands\n\n```bash\ngeni new    # Generate a new migrations file\ngeni up     # Run any pending migration\ngeni down   # Rollback migrations, use --amount to speify how many migrations(default 1)\ngeni create # Create the database, only works for Postgres, MariaDB and MySQL. If you use SQLite will geni create the file before running migrations if the sqlite file don't exist. LibSQL should be create using respective interface.\ngeni drop   # Remove database\ngeni status # Print pending migrations\ngeni help   # Print help message\n```\n\n## Environment variables\n\n- `DATABASE_MIGRATIONS_FOLDER`\n    - Specify where geni should look for migrations to run.\n    - Default: `./migrations`\n- `DATABASE_URL`\n    - The database url geni should use to make migrations\n    - Examples:\n        - Postgres:`DATABASE_URL=\"postgres://postgres@127.0.0.1:5432/app?sslmode=disable\"`\n        - MySQL: `mysql://root:password@localhost:3307/app`\n        - MariaDB: `mariadb://root:password@localhost:3307/app`\n        - Sqlite: `sqlite://./database.sqlite`\n        - LibSQL: `https://localhost:6000`\n            - The protocol for LibSQL is https.\n            - For turso uses: This is something you can retrieve using Turso CLI or the website\n    - When using SSH tunneling, keep `DATABASE_URL` pointed at the remote/private database host. Geni will rewrite it to a local forwarded address at runtime.\n- `DATABASE_SSH_HOST`\n    - Enables SSH tunneling for supported local CLI commands.\n    - Accepts either a raw SSH host or a `~/.ssh/config` host alias.\n    - When you pass an alias, geni uses the system `ssh` client, so OpenSSH settings such as `HostName`, `User`, `Port`, `IdentityAgent`, `ProxyJump`, and related auth settings are honored automatically.\n- `DATABASE_SSH_USER`\n    - Optional SSH username override.\n    - If omitted, OpenSSH config and defaults are used.\n- `DATABASE_SSH_PORT`\n    - Optional SSH port override.\n    - If omitted, OpenSSH config and defaults are used.\n- `DATABASE_SSH_IDENTITY_FILE`\n    - Optional SSH identity file override.\n    - If omitted, geni leaves identity selection to the system `ssh` client, including `ssh-agent` and `IdentityAgent` from `~/.ssh/config`.\n- `DATABASE_SSH_LOCAL_PORT`\n    - Optional local port to bind for the tunnel.\n    - Default: a local port chosen by geni from `60000..=65000`\n- `DATABASE_SSH_REMOTE_HOST`\n    - Optional remote host reachable from the SSH server.\n    - Default: the host from `DATABASE_URL`\n- `DATABASE_SSH_REMOTE_PORT`\n    - Optional remote port reachable from the SSH server.\n    - Default: the port from `DATABASE_URL`, or `5432` for Postgres and `3306` for MySQL/MariaDB\n- `DATABASE_TOKEN`\n    - Only if you use `Turso` and `LibSQL` and require token to authenticate. If not specified will Geni try to migrate without any auth\n- `DATABASE_WAIT_TIMEOUT`\n    - Time for geni to wait before trying to migrate. Useful if your database need some time to boot\n    - Default: `30` seconds\n- `DATABASE_SCHEMA_FILE`\n  - Name of the schema migration file\n- `DATABASE_MIGRATIONS_TABLE`\n  - Name of the table to run migrations to\n## Usage\n\n### Creating a new migration\n\nRunning \n\n```bash\nDATABASE_URL=\"x\" geni new hello_world\n```\n\nWill create 2 files(with path written in console). 1 file ending with `.up.sql` and 1 ending with `.down.sql`. `.up.sql` is for creating migrations and `.down.sql` is for rollbacking migrations. This means that  `.down.sql` should include information that rollback the changed you added to `.up.sql`. \n\nExample:\n\nIf I want to create  table named `Persons` should I add this to `.up.sql`\n\n```sql\nCREATE TABLE Persons (\n    PersonID int\n)\n```\n\nAnd the rollback migration should then be\n\n```sql\nDROP TABLE Persons;\n```\n\nin the generated `.down.sql` file as this code would revert the creation of the table `Persons`\n\n### Transactions\n\nGeni defaults to always run in transactions but if you want to prevent usage of transactions, add `transaction: no` as the first line of the migration file.\nThen Geni won't use transactions for the specific migration.\nThis works for both up and down\n\nExample:\n\n```sql\n-- transaction:no\nCREATE TABLE table_2 (\n  id INT PRIMARY KEY,\n  name VARCHAR(255) NOT NULL,\n  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n```\n\n### Running migration\n\nRunning migration can be done using\n\n```bash\ngeni up\n```\n\nYou can also pass the database URL as a flag instead of an environment variable:\n\n```bash\ngeni --database-url \"postgres://postgres@127.0.0.1:5432/app?sslmode=disable\" up\n```\n\n### Rollback migrations\n\nRollbacking last added migrations can be done using\n\n```bash\ngeni down\n```\n\nand If you want to rollback more then 1 can you add `-a` to the cli to specify how many\n\n```bash\ngeni down -a 3\n```\n\n### Running from CLI\n\n```bash\nDATABASE_URL=\"postgres://postgres@127.0.0.1:5432/app?sslmode=disable\" geni up\n```\n\n### Running through an SSH tunnel\n\nSSH tunneling is supported for local CLI usage with Postgres, MySQL, and MariaDB URLs.\n\nIf you do not specify `--ssh-local-port`, geni will try high local ports in `60000..=65000` until OpenSSH successfully binds one. Use `--ssh-local-port` or `DATABASE_SSH_LOCAL_PORT` if you want a deterministic local port. If that explicit port is already in use, tunnel startup fails immediately.\n\n```bash\ngeni \\\n  --database-url \"postgres://app:secret@db.internal:5432/app?sslmode=disable\" \\\n  --ssh-host \"prod-bastion\" \\\n  up\n```\n\nBecause geni shells out to the system `ssh` client, you can also rely on `~/.ssh/config` for connection details and agent selection. Example with an OpenSSH alias and the 1Password SSH agent:\n\n```sshconfig\nHost vps\n  HostName your-server.example.com\n  User root\n  Port 22\n  IdentityAgent \"~/.1password/agent.sock\"\n```\n\nThen run:\n\n```bash\ngeni \\\n  --database-url \"postgres://app:secret@db.internal:5432/app?sslmode=disable\" \\\n  --ssh-host \"vps\" \\\n  up\n```\n\nIf the database is only reachable as `localhost` from the SSH server, keep the SSH host separate and override the remote target:\n\n```bash\ngeni \\\n  --database-url \"postgres://app:secret@localhost:5432/app?sslmode=disable\" \\\n  --ssh-host \"prod-bastion\" \\\n  --ssh-remote-host \"127.0.0.1\" \\\n  up\n```\n\nV1 tunnel support is local CLI only. The published Docker image and GitHub Action still expect direct database connectivity.\n\n### Github Workflow\n\n```yaml\n- uses: emilpriver/geni@main\n  with:\n    migrations_folder: \"./migrations\"\n    wait_timeout: \"30\"\n    migrations_table: \"schema_migrations\"\n    database_url: \"https://localhost:3000\"\n    database_token: \"X\"\n```\n\n#### Arguments\n  - `migrations_folder`(optional): The path to where your migrations exist.\n    - Default: ./migrations\n  - `wait_timeout`(optional): The time to wait before dropping the attempt to connect to the database\n    - Default: 30\n  - `migrations_table`(optional): The name of the migrations table\n    - Default: `schema_migrations`\n  - database_url(required): The url for accessing your database\n  - database_token(optional): The token used to authenticate towards Turso. Only needed if you need to authenticate yourself\n    - Default: \"\"\n\n### Running in CI/CD\n\nIn a CI/CD should the database_url come from a security store and be appended to the environment as the `DATABASE_URL`. If the `DATABASE_URL` is provided as a environment variable is the only command you need to run\n\n```bash\ngeni up\n```\n\nto make migrations.\n\n## Running Geni as a library\n\nGeni can be used as a library as well.\n\nAll exposed functions can be found in [the library example folder]( ./examples/library/)\n\n```rust\nuse geni;\n\n#[tokio::main]\nasync fn main() {\n    // Migrate the database\n    geni::migrate_database(\n        \"sqlite://./test.db\".to_string(), // Database URL\n        None,                             // Database Token\n        \"migrations\".to_string(),         // Migration Table\n        \"./migrations\".to_string(),       // Migration Folder\n        \"schema.sql\".to_string(),         // Schema File\n        Some(30),                         // Wait timeout for the database to be ready\n        false,                            // Dump Schema\n    )\n    .await\n    .unwrap();\n\n    ()\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femilpriver%2Fgeni","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femilpriver%2Fgeni","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femilpriver%2Fgeni/lists"}