Skip to main content

Overview

The geni dump command exports your current database schema to a SQL file. This creates a snapshot of your database structure that can be used for documentation, version control, or disaster recovery.

Usage

DATABASE_URL="<connection-string>" geni dump

Required Environment Variables

DATABASE_URL
string
required
The database connection string. Format varies by database type.Examples:
  • PostgreSQL: postgres://user:password@localhost:5432/dbname?sslmode=disable
  • MySQL: mysql://root:password@localhost:3306/app
  • MariaDB: mariadb://root:password@localhost:3307/app
  • SQLite: sqlite://./database.sqlite
  • LibSQL: https://localhost:6000

Optional Environment Variables

DATABASE_TOKEN
string
default:"none"
Authentication token for LibSQL/Turso databases.
DATABASE_MIGRATIONS_FOLDER
string
default:"./migrations"
Directory where the schema file will be created.
DATABASE_MIGRATIONS_TABLE
string
default:"schema_migrations"
Name of the migrations tracking table.
DATABASE_SCHEMA_FILE
string
default:"schema.sql"
Name of the output schema file. The file will be created in the migrations folder.
DATABASE_WAIT_TIMEOUT
number
default:"30"
Number of seconds to wait for the database to be ready.

How It Works

  1. Connect to the database
  2. Extract the complete database schema (tables, indexes, constraints, etc.)
  3. Generate SQL statements that recreate the schema
  4. Write the schema to a file in the migrations folder
Schema dumping happens automatically after geni up and geni down unless disabled with DATABASE_NO_DUMP_SCHEMA=true.

Database-Specific Requirements

PostgreSQL

No external dependencies - Uses SQL queries to extract schema
DATABASE_URL="postgres://localhost/app" geni dump

MySQL

⚠️ Requires mysqldump - Must be installed on the system
# Install mysqldump (usually included with MySQL client)
sudo apt-get install mysql-client

# Then run dump
DATABASE_URL="mysql://root:password@localhost:3306/app" geni dump

MariaDB

⚠️ Requires mariadb-dump - Must be installed on the system
# Install mariadb-dump (usually included with MariaDB client)
sudo apt-get install mariadb-client

# Then run dump
DATABASE_URL="mariadb://root:password@localhost:3307/app" geni dump

SQLite

No external dependencies - Uses SQL queries to extract schema
DATABASE_URL="sqlite://./database.sqlite" geni dump

LibSQL

No external dependencies - Uses SQL queries to extract schema
DATABASE_URL="https://localhost:6000" geni dump

Examples

PostgreSQL Dump

DATABASE_URL="postgres://postgres:password@localhost:5432/app?sslmode=disable" geni dump
Output:
Success
Generated file: ./migrations/schema.sql

Custom Schema File Name

DATABASE_URL="postgres://localhost/app" \
DATABASE_SCHEMA_FILE="current_schema.sql" \
geni dump
Generated file: ./migrations/current_schema.sql

Custom Migrations Folder

DATABASE_URL="sqlite://./app.db" \
DATABASE_MIGRATIONS_FOLDER="./db/migrations" \
geni dump
Generated file: ./db/migrations/schema.sql

MySQL with Custom Configuration

DATABASE_URL="mysql://root:password@localhost:3306/app" \
DATABASE_SCHEMA_FILE="mysql_schema.sql" \
DATABASE_MIGRATIONS_FOLDER="./db" \
geni dump

Generated Schema File

The schema file contains SQL statements to recreate your database structure: Example schema.sql (PostgreSQL):
-- Schema dump generated by Geni
-- Database: PostgreSQL

CREATE TABLE schema_migrations (
    version VARCHAR(255) PRIMARY KEY
);

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    name VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content TEXT,
    user_id INTEGER REFERENCES users(id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_posts_user_id ON posts(user_id);

Use Cases

Version Control

Track schema changes in git:
# Dump schema
DATABASE_URL="postgres://localhost/app" geni dump

# Commit to version control
git add migrations/schema.sql
git commit -m "Update schema after adding posts table"
git push

Documentation

Generate up-to-date schema documentation:
# Dump current schema
DATABASE_URL="$PROD_DB" \
DATABASE_SCHEMA_FILE="production_schema.sql" \
geni dump

# Use in documentation
cp migrations/production_schema.sql docs/database/

Disaster Recovery

Maintain schema snapshots:
# Create timestamped schema backup
DATABASE_URL="postgres://localhost/app" \
DATABASE_SCHEMA_FILE="schema_$(date +%Y%m%d_%H%M%S).sql" \
geni dump

Comparing Environments

Compare schemas across environments:
# Dump dev schema
DATABASE_URL="sqlite://./dev.db" \
DATABASE_SCHEMA_FILE="schema_dev.sql" \
geni dump

# Dump production schema
DATABASE_URL="$PROD_DB" \
DATABASE_SCHEMA_FILE="schema_prod.sql" \
geni dump

# Compare
diff migrations/schema_dev.sql migrations/schema_prod.sql

CI/CD Schema Validation

Validate schema in CI:
# In CI pipeline
DATABASE_URL="$TEST_DB" geni up
DATABASE_URL="$TEST_DB" geni dump

# Check if schema changed
if git diff --exit-code migrations/schema.sql; then
  echo "Schema unchanged"
else
  echo "Schema modified - review changes"
  git diff migrations/schema.sql
fi

Automatic Dumping

By default, Geni automatically dumps the schema after running migrations:
# Schema is dumped automatically after 'up'
DATABASE_URL="postgres://localhost/app" geni up
# schema.sql is updated

# Schema is dumped automatically after 'down'
DATABASE_URL="postgres://localhost/app" geni down
# schema.sql is updated

Disable Automatic Dumping

DATABASE_URL="postgres://localhost/app" \
DATABASE_NO_DUMP_SCHEMA="true" \
geni up
# schema.sql is NOT updated

Docker Usage

Standard Docker Image

docker run --rm -it --network=host \
  -v "$(pwd)/migrations:/migrations" \
  -e DATABASE_URL="postgres://localhost/app" \
  ghcr.io/emilpriver/geni:latest dump

Slim Docker Image

The slim Docker image does not include mysqldump or mariadb-dump. Schema dumping will be skipped for MySQL and MariaDB when using the slim image.
# Slim image - no external dump tools
docker run --rm -it --network=host \
  -v "$(pwd)/migrations:/migrations" \
  -e DATABASE_URL="sqlite://./app.db" \
  ghcr.io/emilpriver/geni:latest-slim dump

CI/CD Integration

GitHub Actions

- name: Run migrations and dump schema
  run: |
    DATABASE_URL="${{ secrets.DATABASE_URL }}" geni up
    DATABASE_URL="${{ secrets.DATABASE_URL }}" geni dump

- name: Commit schema changes
  run: |
    git config user.name "GitHub Actions"
    git config user.email "[email protected]"
    git add migrations/schema.sql
    git diff --quiet && git diff --staged --quiet || \
      (git commit -m "Update schema.sql" && git push)

GitLab CI

dump-schema:
  image: ghcr.io/emilpriver/geni:latest
  script:
    - geni dump
  artifacts:
    paths:
      - migrations/schema.sql
    expire_in: 30 days
  variables:
    DATABASE_URL: $DATABASE_URL
  only:
    - main

Error Handling

Missing mysqldump

Error: mysqldump command not found
Solution: Install the MySQL client:
# Ubuntu/Debian
sudo apt-get install mysql-client

# macOS
brew install mysql-client

# Alpine (Docker)
apk add mysql-client

Missing mariadb-dump

Error: mariadb-dump command not found
Solution: Install the MariaDB client:
# Ubuntu/Debian
sudo apt-get install mariadb-client

# Alpine (Docker)
apk add mariadb-client

Permission Denied

Error: Permission denied (os error 13)
Solution: Ensure you have write permissions to the migrations folder:
chmod +w migrations/

Best Practices

  • Version control: Always commit schema.sql to your repository
  • Regular dumps: Run geni dump after significant schema changes
  • Use in CI: Automate schema dumping in your CI/CD pipeline
  • Review changes: Check schema diffs before committing
  • Timestamp backups: Create timestamped schema files for archival
  • Compare environments: Use dumps to verify staging matches production
  • Document structure: Include schema files in your documentation
  • Slim images: Use the full Docker image if you need MySQL/MariaDB dumping

Automation Scripts

Automated Schema Backup

#!/bin/bash
set -e

DATABASE_URL="postgres://localhost/app"
BACKUP_DIR="./schema_backups"

mkdir -p "$BACKUP_DIR"

# Create timestamped backup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
DATABASE_URL="$DATABASE_URL" \
DATABASE_SCHEMA_FILE="schema_${TIMESTAMP}.sql" \
DATABASE_MIGRATIONS_FOLDER="$BACKUP_DIR" \
geni dump

echo "Schema backed up to: $BACKUP_DIR/schema_${TIMESTAMP}.sql"

# Keep only last 30 backups
ls -t "$BACKUP_DIR"/schema_*.sql | tail -n +31 | xargs -r rm

Make Commands

.PHONY: schema-dump
schema-dump:
	@echo "Dumping database schema..."
	@DATABASE_URL="$(DATABASE_URL)" geni dump
	@echo "Schema saved to migrations/schema.sql"

.PHONY: schema-backup
schema-backup:
	@mkdir -p schema_backups
	@DATABASE_URL="$(DATABASE_URL)" \
	  DATABASE_SCHEMA_FILE="schema_$$(date +%Y%m%d_%H%M%S).sql" \
	  DATABASE_MIGRATIONS_FOLDER="./schema_backups" \
	  geni dump
	@echo "Schema backup created"

Next Steps

Run Migrations

Apply migrations with geni up

Check Status

View migration status with geni status

Create Migration

Create new migrations with geni new

Rollback

Rollback migrations with geni down

Build docs developers (and LLMs) love