Grove
1.x
Docs/Grove/Migrating from Bun
Open

Reading3 min
Updated31 Jul 2026
Sourcev1/guides/bun-migration.mdx

Grove is designed for seamless migration from bun. Existing bun models work with Grove unchanged thanks to the dual tag system.

Step 1: Add Grove Dependency01

go get github.com/xraph/grove

Step 2: Swap the Import02

Replace bun.BaseModel with grove.BaseModel:

// Before
import "github.com/uptrace/bun"

type User struct {
    bun.BaseModel `bun:"table:users,alias:u"`
    ID   int64  `bun:"id,pk,autoincrement"`
    Name string `bun:"name,notnull"`
}

// After — bun tags still work!
import "github.com/xraph/grove"

type User struct {
    grove.BaseModel `bun:"table:users,alias:u"`
    ID   int64  `bun:"id,pk,autoincrement"`
    Name string `bun:"name,notnull"`
}

Step 3: Replace the DB Connection03

// Before (bun)
sqldb, _ := sql.Open("pgx", dsn)
db := bun.NewDB(sqldb, pgdialect.New())

// After (grove)
pgdb := pgdriver.New()
pgdb.Open(ctx, dsn, driver.WithPoolSize(20))
db, _ := grove.Open(pgdb)

Step 4: Update Query Syntax04

Most bun query patterns have direct Grove equivalents:

BunGrove
db.NewSelect(&users).Where("? = ?", bun.Ident("active"), true)db.NewSelect(&users).Where("active = $1", true)
db.NewInsert(&user).Exec(ctx)db.NewInsert(&user).Exec(ctx)
db.NewUpdate(&user).WherePK().Exec(ctx)db.NewUpdate(&user).WherePK().Exec(ctx)
db.NewDelete(&user).WherePK().Exec(ctx)db.NewDelete(&user).WherePK().Exec(ctx)

Key difference: Grove uses native PostgreSQL $1 placeholders instead of bun's ? with bun.Ident().

Step 5: Incrementally Adopt Grove Tags05

Once your project works with Grove, you can gradually migrate tags to access extended features:

type User struct {
    grove.BaseModel `grove:"table:users,alias:u"`          // Migrated

    ID    int64  `grove:"id,pk,autoincrement"`              // Migrated
    Name  string `bun:"name,notnull"`                       // Still bun — works fine
    Email string `grove:"email,notnull,unique"`              // Migrated
    SSN   string `grove:"ssn,privacy:pii"`                   // New: privacy tag
}

Step 6: Add Grove Features06

After migration, take advantage of Grove-specific features:

Privacy Hooks

db.Hooks().AddHook(&hook.TenantIsolation{Column: "tenant_id"})

Modular Migrations

var Migrations = migrate.NewGroup("myapp")
// Register Go-code migrations with dependency ordering

Multi-Driver Support

// Same models work across databases
pgdb := pgdriver.New()
pgdb.Open(ctx, pgDSN, driver.WithPoolSize(20))
pgDB, _ := grove.Open(pgdb)

mydb := mysqldriver.New()
mydb.Open(ctx, myDSN, driver.WithPoolSize(20))
myDB, _ := grove.Open(mydb)

What Changes07

FeatureBunGrove
Placeholders?Native per driver ($1, ?)
Tag namespacebun:"..."grove:"..." (bun fallback)
Privacy tagsNot availableprivacy:pii, privacy:sensitive
Multi-driverPostgreSQL-focusedPG, MySQL, SQLite, MongoDB
MigrationsSQL filesGo code with dependency ordering
HooksQuery hooksPrivacy hooks with deny/modify/filter

What Stays the Same08

  • Model structure and field definitions

  • Relation tags (has-one, has-many, belongs-to, many-to-many)

  • Query builder patterns (NewSelect, NewInsert, NewUpdate, NewDelete)

  • Soft delete behavior

  • Transaction API