Skip to content

hymns/go-artisan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

12 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Artisan - Database Migration Tool for Go

Artisan is a powerful, Laravel-inspired database migration tool for Go that provides an elegant and intuitive way to manage database migrations and seeders.

Go Version License

Table of Contents

Features

  • βœ… Multi-Database Support - MySQL, PostgreSQL, SQL Server, SQLite
  • βœ… Batch Tracking - Rollback migrations by batch, not one-by-one
  • βœ… Transaction Safety - Each migration runs in a transaction (atomic)
  • βœ… Migration Locking - Prevents concurrent migrations
  • βœ… SQL-Based Migrations - Simple SQL files, no Go code needed
  • βœ… Multi-Statement Support - Execute multiple SQL statements per migration
  • βœ… Laravel-Style Commands - Familiar syntax for Laravel developers
  • βœ… Auto-Naming - Smart migration name generation
  • βœ… Built-in Seeders - Seed your database with test data
  • βœ… Seeder Tracking - Skip already-run seeders automatically
  • βœ… Driver-Specific SQL - Auto-generate correct SQL for your database
  • βœ… Migration Status - See which migrations are pending/ran
  • βœ… Seeder Status - See which seeders are pending/seeded
  • βœ… Dry Run Mode - Preview migrations before running

πŸ“¦ Installation

go get github.com/hymns/go-artisan

Or clone and build:

git clone https://github.com/hymns/go-artisan.git
cd go-artisan
make build

Install globally:

make install
# or
sudo cp bin/artisan /usr/local/bin/

🎯 Quick Start

1. Setup Configuration

Copy the example configuration file and customize it:

# Copy example configuration
cp .env.example .env

# Edit .env with your database credentials

Example .env configuration:

DB_DRIVER=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=your_database
DB_USERNAME=root
DB_PASSWORD=

MIGRATIONS_PATH=./database/migrations
SEEDERS_PATH=./database/seeders

Note: Artisan supports alternate environment variable names for compatibility:

  • DB_DATABASE or DB_NAME (primary: DB_DATABASE)
  • DB_USERNAME or DB_USER (primary: DB_USERNAME)
  • DB_PASSWORD or DB_PASS (primary: DB_PASSWORD)

See Multi-Database Support section for PostgreSQL, SQL Server, and SQLite configuration.

2. Create Your First Migration

# Simple table name (auto-generates: create_users_table)
artisan make:migration users
# Output: 2026_01_16_170530_create_users_table

# Custom migration name with prefix
artisan make:migration create_products_table
# Output: 2026_01_16_170530_create_products_table

# Custom name with --table parameter
artisan make:migration add_status_column --table=users
# Output: 2026_01_16_170530_add_status_column

3. Edit the Migration

-- Migration: create_users_table
-- Database: mysql

--UP--
CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

CREATE INDEX idx_users_email ON users(email);

--DOWN--
DROP TABLE IF EXISTS users;

4. Run Migrations

artisan migrate
# βœ“ Migrated: 2026_01_16_170530_create_users_table

5. Create and Run Seeders

artisan make:seeder users
# βœ“ Seeder created: users_seeder

# Edit database/seeders/users_seeder
# Then run:
artisan db:seed
# βœ“ Seeded: users_seeder

πŸ“š Commands

Migration Commands

# Simple table name (auto-generates: create_<table>_table)
artisan make:migration users
# Result: 2026_01_25_105530_create_users_table

artisan make:migration products  
# Result: 2026_01_25_105545_create_products_table

# Custom migration name with prefix words (create/alter/add/drop/rename)
artisan make:migration create_orders_table
# Result: 2026_01_25_105600_create_orders_table

artisan make:migration add_status_to_users
# Result: 2026_01_25_105615_add_status_to_users

# Custom name with --table parameter (specifies table in migration content)
artisan make:migration add_email_verified --table=users
# Result: 2026_01_25_105630_add_email_verified

# Run all pending migrations
artisan migrate

# Run specific migration file
artisan migrate --path=./database/migrations/2026_01_16_170530_create_users_table

# Run migrations and seeders
artisan migrate --seed

# Rollback last batch (default: 1 step)
artisan migrate:rollback

# Rollback N batches
artisan migrate:rollback --step=3

# Rollback all, then re-run migrations (fresh start)
artisan migrate:fresh

# Rollback all, migrate, then seed (fresh system)
artisan migrate:fresh --seed

# Show migration status
artisan migrate:status

# Preview pending migrations (dry run)
artisan migrate:dry-run

Seeder Commands

# Create seeder (auto-appends _seeder)
artisan make:seeder users
# Output: users_seeder

# Using flags
artisan make:seeder --seeder=products

# Run all seeders (with tracking - skips already seeded)
artisan db:seed
# βœ“ Seeded: users_seeder
# ⚠ Already seeded: products_seeder

# Run specific seeder file
artisan db:seed --path=./database/seeders/users_seeder

# Show seeder status
artisan seeder:status

Makefile Shortcuts

make build      # Build binary
make migrate    # Auto-build + migrate
make rollback   # Auto-build + rollback
make seed       # Auto-build + seed
make install    # Install globally

πŸ—„οΈ Multi-Database Support

Artisan supports MySQL, PostgreSQL, SQL Server, and SQLite out of the box.

MySQL Configuration

DB_DRIVER=mysql
DB_HOST=localhost
DB_PORT=3306
DB_NAME=mydb
DB_USER=root
DB_PASS=secret

PostgreSQL Configuration

DB_DRIVER=postgres
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mydb
DB_USER=postgres
DB_PASS=secret

SQL Server Configuration

DB_DRIVER=sqlserver
DB_HOST=localhost
DB_PORT=1433
DB_NAME=mydb
DB_USER=sa
DB_PASS=secret

SQLite Configuration

DB_DRIVER=sqlite3
DB_NAME=./database.db

Driver-Specific SQL Generation

Artisan automatically generates the correct SQL syntax for your database:

MySQL:

CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

PostgreSQL:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

SQL Server:

CREATE TABLE users (
    id INT IDENTITY(1,1) PRIMARY KEY,
    created_at DATETIME DEFAULT GETDATE(),
    updated_at DATETIME DEFAULT GETDATE()
);

SQLite:

CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

πŸŽ‰ New in v1.3.0

Smart .env Loading

Artisan now automatically loads .env file from the current working directory when installed globally:

# Install globally
sudo cp bin/artisan /usr/local/bin/artisan

# Run from any project directory
cd /path/to/your/project
artisan migrate
# βœ“ Automatically loads .env from current directory

Benefits:

  • βœ… Works from any directory in your project
  • βœ… No need to specify config path
  • βœ… Seamless global installation support

Alternate Environment Variable Names

Support for multiple environment variable naming conventions with fallback support:

# Primary names (recommended)
DB_DATABASE=myapp
DB_USERNAME=root
DB_PASSWORD=secret

# Alternate names (also supported)
DB_NAME=myapp
DB_USER=root
DB_PASS=secret

Priority:

  • DB_DATABASE takes precedence over DB_NAME
  • DB_USERNAME takes precedence over DB_USER
  • DB_PASSWORD takes precedence over DB_PASS

Benefits:

  • βœ… Compatible with Laravel and other frameworks
  • βœ… Flexible configuration options
  • βœ… Backward compatibility maintained

πŸŽ‰ New in v1.2.0

Transaction Safety

All migrations and seeders now run in transactions for atomic operations:

// Each migration runs in a transaction
// If any statement fails, entire migration rolls back
artisan migrate

Benefits:

  • βœ… All-or-nothing execution
  • βœ… Automatic rollback on error
  • βœ… Data integrity guaranteed

Migration Locking

Prevents concurrent migrations from running simultaneously:

# Terminal 1
artisan migrate
# Running...

# Terminal 2
artisan migrate
# βœ— migration is already running by another process

Migration Status Command

See which migrations have been run and which are pending:

artisan migrate:status

Output:

Migration Status:

Migration                                          Batch      Ran
----------------------------------------------------------------------
2026_01_16_170530_create_users_table              1          YES
2026_01_16_170545_create_posts_table              1          YES
2026_01_16_180230_add_user_roles                  -          NO
  • Green YES = Migration has been run
  • Yellow NO = Migration is pending
  • Batch = Which batch the migration was run in (for rollback)

Dry Run Mode

Preview what migrations will run without executing them:

artisan migrate:dry-run

Output:

=== Dry Run - No changes will be made ===

Would migrate: 2026_01_16_180230_add_user_roles (Batch 2)
  Statement 1: ALTER TABLE users ADD COLUMN role VARCHAR(50) DEFAULT 'user'...
  Statement 2: CREATE INDEX idx_users_role ON users(role)...

Total pending migrations: 1

Seeder Status Command

See which seeders have been run and which are pending:

artisan seeder:status

Output:

Seeder Status:

Seeder                                             Ran
------------------------------------------------------------
users_seeder                                       YES
products_seeder                                    YES
categories_seeder                                  NO
  • Green YES = Seeder has been run
  • Yellow NO = Seeder is pending

Seeder Tracking System

Seeders now track execution to prevent duplicate data:

# First run
artisan db:seed
# βœ“ Seeded: users_seeder
# βœ“ Seeded: products_seeder

# Second run (skips already seeded)
artisan db:seed
# ⚠ Already seeded: users_seeder
# ⚠ Already seeded: products_seeder
# Nothing to seed.

Benefits:

  • βœ… Prevents duplicate data insertion
  • βœ… Safe to run multiple times
  • βœ… Tracks seeded files in seeders table
  • βœ… Production-ready

Database Placeholder Compatibility

Fixed SQL placeholder compatibility for all databases:

  • MySQL/SQLite: ?
  • PostgreSQL: $1, $2, $3
  • SQL Server: @p1, @p2, @p3

Human-Readable Migration Names

Migration filenames now use date-based format:

Old: 1768501234_create_users_table
New: 2026_01_16_170530_create_users_table

Format: YYYY_MM_DD_HHMMSS_migration_name

Benefits:

  • βœ… Easy to identify when migration was created
  • βœ… Human-readable at a glance
  • βœ… Still sortable chronologically

πŸ†š Artisan vs golang-migrate

Feature Artisan v1.4.0 golang-migrate
Batch Tracking βœ… Yes ❌ No
Rollback by Batch βœ… Yes ❌ No (one-by-one only)
Transaction Safety βœ… Yes βœ… Yes
Migration Locking βœ… Yes βœ… Yes
Migration Status βœ… Yes ❌ No
Seeder Status βœ… Yes ❌ No
Seeder Tracking βœ… Yes ❌ No
Dry Run Mode βœ… Yes ❌ No
Multi-Statement Support βœ… Yes ⚠️ Limited
Auto-Naming βœ… Yes ❌ No
Built-in Seeders βœ… Yes ❌ No
Laravel-Style Commands βœ… Yes ❌ No
Human-Readable Filenames βœ… Yes (date-based) ❌ No (Unix timestamp)
Driver-Specific Templates βœ… Yes ❌ No
Multi-Database Support βœ… MySQL, Postgres, SQLite βœ… Many drivers
SQL-Based βœ… Pure SQL βœ… Pure SQL
Migration Format Simple text files Up/Down separate files

Why Choose Artisan?

1. Batch Tracking System

Artisan:

artisan migrate
# Batch 1: users, posts, comments

artisan migrate:rollback
# Rolls back entire Batch 1 (all 3 migrations)

golang-migrate:

migrate up
# Migration 1, 2, 3

migrate down 1
# Only rolls back migration 3
# Need to run 3 times to rollback all

2. Multi-Statement Migrations

Artisan:

--UP--
CREATE TABLE users (...);
CREATE TABLE posts (...);
CREATE INDEX idx_users_email ON users(email);
INSERT INTO users (name) VALUES ('Admin');

--DOWN--
DROP TABLE posts;
DROP TABLE users;

All statements execute in one migration file!

3. Laravel-Style Workflow

Artisan:

artisan make:migration users          # Auto-names: create_users_table
artisan migrate                       # Run migrations
artisan migrate:rollback --step=2     # Rollback 2 batches
artisan make:seeder users             # Create seeder
artisan db:seed                       # Run seeders

golang-migrate:

migrate create -ext sql -dir migrations create_users_table
migrate -path migrations -database "mysql://..." up
migrate -path migrations -database "mysql://..." down 1
# No built-in seeder support

4. Smart Auto-Naming

Artisan:

artisan make:migration products
# Creates: 2026_01_16_170530_create_products_table

artisan make:migration products add_price_column
# Creates: 2026_01_16_170545_add_price_column

5. Built-in Seeder System

Artisan:

artisan make:seeder products
# Edit SQL file
artisan db:seed
# βœ“ Seeded: products_seeder (tracked - won't duplicate)

artisan seeder:status
# See which seeders are pending/seeded

golang-migrate: No built-in seeder support. Need separate tools or custom scripts.

πŸ”§ Programmatic Usage

Auto-Migration on Application Startup

You can integrate go-artisan into your Go application to automatically run migrations when your app starts:

package main

import (
    "database/sql"
    "log"
    
    _ "github.com/go-sql-driver/mysql"
    "github.com/hymns/go-artisan/migration"
)

func main() {
    // Connect to database
    db, err := sql.Open("mysql", "user:pass@tcp(localhost:3306)/dbname?parseTime=true")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    // Auto-run migrations on startup (safe - idempotent)
    m := migration.New(db)
    if err := m.AutoMigrate("./database/migrations"); err != nil {
        log.Fatal(err)
    }
    
    // Auto-run seeders on startup (safe - with tracking)
    s := seeder.New(db)
    if err := s.AutoSeed("./database/seeders"); err != nil {
        log.Fatal(err)
    }
    
    // Your application code here...
}

Key Features:

  • βœ… Silent Execution - No console output, only returns errors
  • βœ… Production Ready - Safe to run on every app startup
  • βœ… Idempotent - Only runs pending migrations and seeders
  • βœ… Fast - Skips already migrated/seeded files
  • βœ… Seeder Tracking - Tracks seeded files to prevent duplicates

βœ… Safe: Both AutoMigrate and AutoSeed use tracking tables to prevent duplicates. Safe to run on every app startup!

Migration Methods

AutoMigrate(path string) - Silent migration for production apps

if err := m.AutoMigrate("./database/migrations"); err != nil {
    log.Fatal(err)
}

Migrate(path string) - Migration with colored console output

if err := m.Migrate("./database/migrations"); err != nil {
    log.Fatal(err)
}
// Output: βœ“ Migrated: 2026_01_16_170530_create_users_table

MigrateFile(filePath string) - Run specific migration file

// Run a specific migration file
if err := m.MigrateFile("./database/migrations/2026_01_16_170530_create_users_table"); err != nil {
    log.Fatal(err)
}
// Output: βœ“ Migrated: 2026_01_16_170530_create_users_table

Use Cases for MigrateFile:

  • Testing specific migrations in development
  • Running hotfix migrations in production
  • Conditional migration execution based on app logic
  • Debugging migration issues

Seeder Methods

AutoSeed(path string) - Silent seeding with tracking (NEW!)

// Safe to run on every app startup - tracks seeded files
s := seeder.New(db)
if err := s.AutoSeed("./database/seeders"); err != nil {
    log.Fatal(err)
}

Features:

  • βœ… Idempotent - Skips already-seeded files
  • βœ… Tracking Table - Uses seeders table to track execution
  • βœ… Silent - No console output
  • βœ… Production Safe - Won't duplicate data on restart

RunWithTracking(path string) - Run with tracking and colored output (used by db:seed)

// Shows which seeders are skipped vs newly seeded
s := seeder.New(db)
if err := s.RunWithTracking("./database/seeders"); err != nil {
    log.Fatal(err)
}
// Output: ⚠ Already seeded: users_seeder
// Output: βœ“ Seeded: products_seeder
// Output: Nothing to seed. (if all already seeded)

Run(path string) - Run all seeders WITHOUT tracking

// ⚠️ WARNING: Will duplicate data if run multiple times
s := seeder.New(db)
if err := s.Run("./database/seeders"); err != nil {
    log.Fatal(err)
}
// Output: βœ“ Seeded: users_seeder

RunFile(filePath string) - Run specific seeder file WITHOUT tracking

// ⚠️ WARNING: Will duplicate data if run multiple times
s := seeder.New(db)
if err := s.RunFile("./database/seeders/users_seeder"); err != nil {
    log.Fatal(err)
}
// Output: βœ“ Seeded: users_seeder

Use Cases:

  • AutoSeed - Production apps, auto-run on startup
  • RunWithTracking - Development, see what's already seeded
  • Run - One-time seeding, test data that can be wiped
  • RunFile - Specific seeder for testing/debugging

πŸ“– Advanced Usage

Complex Migrations

--UP--
-- Create main table
CREATE TABLE orders (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    user_id INTEGER NOT NULL,
    total DECIMAL(10,2),
    status ENUM('pending', 'completed', 'cancelled'),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Create related table
CREATE TABLE order_items (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    order_id INTEGER NOT NULL,
    product_id INTEGER NOT NULL,
    quantity INTEGER DEFAULT 1,
    price DECIMAL(10,2),
    FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
);

-- Add indexes
CREATE INDEX idx_orders_user ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_order_items_order ON order_items(order_id);

--DOWN--
DROP TABLE IF EXISTS order_items;
DROP TABLE IF EXISTS orders;

Seeders with Multiple Statements

-- Seeder: products_seeder

INSERT INTO products (name, price) VALUES 
    ('Product 1', 99.99),
    ('Product 2', 149.99),
    ('Product 3', 199.99);

INSERT INTO categories (name) VALUES 
    ('Electronics'),
    ('Books'),
    ('Clothing');

UPDATE products SET category_id = 1 WHERE id = 1;

Environment-Specific Configurations

# Development
cp .env.example .env.dev
# Set DB_DRIVER=sqlite3, DB_NAME=./dev.db

# Testing
cp .env.example .env.test
# Set DB_DRIVER=sqlite3, DB_NAME=./test.db

# Production
cp .env.example .env.prod
# Set DB_DRIVER=postgres with production credentials

πŸ—οΈ Project Structure

your-project/
β”œβ”€β”€ bin/
β”‚   └── artisan              # Compiled binary (after make build)
β”œβ”€β”€ database/
β”‚   β”œβ”€β”€ migrations/          # Migration files (created via make:migration)
β”‚   β”‚   └── ...              # e.g., 1768501234_create_users_table
β”‚   └── seeders/             # Seeder files (created via make:seeder)
β”‚       └── ...              # e.g., users_seeder
β”œβ”€β”€ .env                     # Database configuration (copy from .env.example)
└── Makefile                 # Build shortcuts (optional)

πŸ› οΈ Development

Build from Source

git clone https://github.com/hymns/go-artisan.git
cd go-artisan
make deps    # Install dependencies
make build   # Build binary
make test    # Run tests

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ‘¨β€πŸ’» Author

Muhammad Hamizi Jaminan

A passionate Go developer who loves building developer tools and bringing the best of Laravel's ecosystem to the Go community.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

Inspired by:

πŸ“ž Support


Made with ❀️ for Go developers who miss Laravel's migration system.

About

Artisan - Database Migration Tool for Go

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors