Jone
A @knex inspired SQL migration and schema builder for Go. Supports PostgreSQL today, Others coming soon. Designed to be flexible, and fun to use.
Install / Use
/learn @Grandbusta/JoneREADME
Jone
A Go database migration tool with a fluent schema builder. Supports PostgreSQL and MySQL.
📦 Installation
1. Install the CLI (one-time, adds jone command to your system):
go install github.com/Grandbusta/jone/cmd/jone@latest
2. Add library to your project (run in your project directory):
go get github.com/Grandbusta/jone
🚀 Quick Start
# Initialize jone in your project (defaults to postgres)
jone init
# Create a migration
jone migrate:make create_users
# Run all pending migrations
jone migrate:latest
# View migration status
jone migrate:list
💻 CLI Commands
| Command | Description |
|---------|-------------|
| jone init | Initialize jone project. Creates jone/ folder and config. |
| jone migrate:make <name> | Create a new migration file. |
| jone migrate:latest | Run all pending migrations. |
| jone migrate:up [name] | Run next pending migration (or specific one). |
| jone migrate:down [name] | Rollback last migration (or specific one). |
| jone migrate:rollback | Rollback last batch of migrations. |
| jone migrate:list | List all migrations with status. |
| jone migrate:status | Alias for migrate:list. |
Flags
jone init
--db,-d— Database type:postgres,mysql,sqlite(default:postgres)
jone migrate:latest, migrate:up, migrate:down, migrate:rollback
--dry-run— Show SQL that would be executed without running it
jone migrate:rollback
--all,-a— Rollback all migrations (not just last batch)
⚙️ Configuration
After running jone init, edit jone/jonefile.go:
PostgreSQL:
package jone
import (
"github.com/Grandbusta/jone"
_ "github.com/jackc/pgx/v5/stdlib" // PostgreSQL driver
)
var Config = jone.Config{
Client: "postgresql",
Connection: jone.Connection{
Host: "localhost",
Port: "5432",
User: "postgres",
Password: "password",
Database: "my_db",
},
Migrations: jone.Migrations{
TableName: "jone_migrations",
},
}
MySQL:
package jone
import (
"github.com/Grandbusta/jone"
_ "github.com/go-sql-driver/mysql" // MySQL driver
)
var Config = jone.Config{
Client: "mysql",
Connection: jone.Connection{
Host: "localhost",
Port: "3306",
User: "root",
Password: "password",
Database: "my_db",
},
Migrations: jone.Migrations{
TableName: "jone_migrations",
},
}
🔗 Connection Pooling
Jone leverages Go's built-in database/sql connection pool. You can configure pool behavior by adding a Pool field to your config:
import (
"time"
"github.com/Grandbusta/jone"
_ "github.com/jackc/pgx/v5/stdlib" // Driver
)
var Config = jone.Config{
Client: "postgresql",
Connection: jone.Connection{
Host: "localhost",
Port: "5432",
User: "postgres",
Password: "password",
Database: "my_db",
},
Pool: jone.Pool{
MaxOpenConns: 10, // Max open connections (0 = unlimited)
MaxIdleConns: 5, // Max idle connections (0 = default 2)
ConnMaxLifetime: 30 * time.Minute, // Max connection reuse time (0 = no limit)
ConnMaxIdleTime: 5 * time.Minute, // Max idle time before close (0 = no limit)
},
Migrations: jone.Migrations{
TableName: "jone_migrations",
},
}
All fields are optional. Omitting Pool (or using zero values) preserves the database/sql defaults.
🏗️ Schema Builder
Creating Tables
func Up(s *jone.Schema) {
s.CreateTable("users", func(t *jone.Table) {
t.Increments("id")
t.String("name").Length(100).NotNullable()
t.String("email").Length(255).NotNullable().Unique()
t.Text("bio").Nullable()
t.Boolean("active").Default(true)
t.Timestamps() // created_at, updated_at
})
}
Column Types
| Method | SQL Type |
|--------|----------|
| Increments(name) | SERIAL / AUTO_INCREMENT PRIMARY KEY |
| String(name) | VARCHAR(255) |
| Text(name) | TEXT |
| Int(name) | INTEGER |
| BigInt(name) | BIGINT |
| SmallInt(name) | SMALLINT |
| Boolean(name) | BOOLEAN |
| Float(name) | REAL / FLOAT |
| Double(name) | DOUBLE PRECISION |
| Decimal(name) | DECIMAL |
| Date(name) | DATE |
| Time(name) | TIME |
| Timestamp(name) | TIMESTAMP |
| UUID(name) | UUID |
| JSON(name) | JSON |
| JSONB(name) | JSONB |
| Binary(name) | BYTEA / BLOB |
Column Modifiers
t.String("name").Length(100) // Set length
t.String("email").NotNullable() // NOT NULL
t.String("status").Default("new") // Default value
t.String("code").Unique() // Unique constraint
t.String("notes").Nullable() // Explicitly nullable
t.String("title").Comment("...") // Column comment
t.BigInt("user_id").Unsigned() // Unsigned (MySQL)
t.BigInt("id").Primary() // Primary key
t.Decimal("price").Precision(10).Scale(2) // DECIMAL(10,2)
Indexes
// Create index
t.Index("email")
t.Index("first_name", "last_name").Name("idx_full_name")
t.Index("data").Using("gin") // Index method (btree, hash, gin, gist)
// Unique index
t.Unique("email")
t.Unique("org_id", "slug").Name("uq_org_slug")
Foreign Keys
t.BigInt("user_id").NotNullable()
t.Foreign("user_id").References("users", "id").OnDelete("CASCADE")
t.Foreign("org_id").References("orgs", "id").OnDelete("SET NULL").OnUpdate("CASCADE")
t.Foreign("custom").References("table", "col").Name("fk_custom_name")
Timestamps
t.Timestamps() // Adds created_at and updated_at
Altering Tables
func Up(s *jone.Schema) {
s.Table("users", func(t *jone.Table) {
t.String("phone").Nullable() // Add column
t.DropColumn("legacy_field") // Drop column
t.RenameColumn("name", "full_name") // Rename column
t.SetNullable("bio") // Make nullable
t.DropNullable("email") // Make not nullable
t.SetDefault("active", true) // Set default
t.DropDefault("active") // Drop default
t.DropIndex("email") // Drop index
t.DropForeign("user_id") // Drop foreign key
})
}
Dropping Tables
func Down(s *jone.Schema) {
s.DropTable("users")
// or
s.DropTableIfExists("users")
}
Other Operations
s.RenameTable("old_name", "new_name")
s.HasTable("users") // Check if table exists
s.HasColumn("users", "email") // Check if column exists
Raw SQL
For custom statements the schema builder doesn't support:
// DDL statements
s.Raw("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"")
s.Raw("CREATE INDEX CONCURRENTLY idx_users_email ON users(email)")
// Data migrations with parameters
s.Raw("INSERT INTO settings (key, value) VALUES ($1, $2)", "version", "1.0")
s.Raw("UPDATE users SET status = $1 WHERE created_at < $2", "legacy", "2020-01-01")
📝 Migration Example
// jone/migrations/20260123000000_create_users/migration.go
package m20260123000000
import "github.com/Grandbusta/jone"
func Up(s *jone.Schema) {
s.CreateTable("users", func(t *jone.Table) {
t.Increments("id")
t.String("email").NotNullable().Unique()
t.String("password_hash").NotNullable()
t.String("name").Length(100)
t.Boolean("verified").Default(false)
t.Timestamps()
})
s.CreateTable("posts", func(t *jone.Table) {
t.Increments("id")
t.BigInt("user_id").NotNullable()
t.String("title").NotNullable()
t.Text("content")
t.Timestamps()
t.Foreign("user_id").References("users", "id").OnDelete("CASCADE")
t.Index("user_id")
})
}
func Down(s *jone.Schema) {
s.DropTableIfExists("posts")
s.DropTableIfExists("users")
}
🗄️ Supported Databases
| Database | Driver Package | Status |
|----------|----------------|--------|
| PostgreSQL | github.com/jackc/pgx/v5/stdlib | ✅ Supported |
| MySQL | github.com/go-sql-driver/mysql | ✅ Supported |
| SQLite | github.com/mattn/go-sqlite3 | 🚧 Planned |
🤝 Contributing
Contributions are welcome! Please see our Contributing Guide for more details.
📄 License
MIT
Related Skills
oracle
352.9kBest practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns).
xurl
352.9kA CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.
prose
352.9kOpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows.
Command Development
111.5kThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
