Skip to main content

Overview

The geni new command generates a pair of timestamped migration files for your database changes. Each migration consists of an “up” file for applying changes and a “down” file for rolling them back.

Usage

geni new <name>

Arguments

name
string
required
The name of the migration. Spaces will be converted to underscores and the name will be lowercased.Examples:
  • create_users_table
  • add email column
  • CreateIndexOnPosts

How It Works

  1. Generates a Unix timestamp for versioning
  2. Creates two files in your migrations folder:
    • {timestamp}_{name}.up.sql - For applying the migration
    • {timestamp}_{name}.down.sql - For rolling back the migration
  3. Each file contains a starter comment template

Environment Variables

DATABASE_MIGRATIONS_FOLDER
string
default:"./migrations"
Specifies the directory where migration files will be created. The folder will be created automatically if it doesn’t exist.

Examples

Basic Usage

Create a migration to add a users table:
geni new create_users_table
Output:
Generated ./migrations/1709395200_create_users_table.up.sql
Generated ./migrations/1709395200_create_users_table.down.sql
Success

Using Custom Migration Folder

DATABASE_MIGRATIONS_FOLDER="./db/migrations" geni new add_index_to_posts
Output:
Generated ./db/migrations/1709395245_add_index_to_posts.up.sql
Generated ./db/migrations/1709395245_add_index_to_posts.down.sql
Success

Migration with Spaces

geni new "Add Email Column"
Output:
Generated ./migrations/1709395300_add_email_column.up.sql
Generated ./migrations/1709395300_add_email_column.down.sql
Success

Generated File Contents

Each generated file contains a template comment: _create_users_table.up.sql:
-- Write your up sql migration here
_create_users_table.down.sql:
-- Write your down sql migration here

Writing Migrations

After creating migration files, you need to add your SQL:

Up Migration Example

-- Write your up sql migration here
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    name VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_users_email ON users(email);

Down Migration Example

-- Write your down sql migration here
DROP INDEX IF EXISTS idx_users_email;
DROP TABLE IF EXISTS users;
The down migration should reverse all changes made in the up migration to ensure clean rollbacks.

Transaction Control

By default, Geni runs migrations in transactions. To disable transactions for a specific migration, add a comment at the top of the file:
-- transaction:no
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL
);
Some database operations (like creating indexes concurrently in PostgreSQL) cannot run inside transactions. Use -- transaction:no for these cases.

Best Practices

  • Use descriptive names: Choose names that clearly describe what the migration does
  • Keep migrations small: Focus on one logical change per migration
  • Test rollbacks: Always ensure your down migration properly reverses the up migration
  • Avoid manual timestamps: Let Geni generate timestamps to prevent conflicts
  • Version control: Commit migration files to your repository

Common Patterns

Creating a Table

geni new create_posts_table

Altering a Table

geni new add_published_to_posts

Adding an Index

geni new add_index_on_user_email

Data Migration

geni new migrate_user_preferences

Next Steps

Apply Migrations

Run pending migrations with geni up

Check Status

View pending migrations with geni status

Build docs developers (and LLMs) love