No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-21 22:17:15 +08:00
.github chore(ci): update GitHub Actions to latest versions (#1424) 2026-08-21 15:43:49 +08:00
dbfixture chore: release v1.2.18 (release.sh) (#1341) 2026-02-28 13:06:26 +02:00
dialect refactor: use reflect.Pointer instead of reflect.Ptr (#1426) 2026-08-21 16:07:50 +08:00
driver fix(pgdriver): verify server certificate for WithInsecure(false) (#1402) 2026-07-22 16:43:29 +08:00
example docs: update examples to use WithQueryHook instead of deprecated AddQueryHook (#1355) 2026-04-02 11:18:04 +08:00
extra fix(bunotel): honor WithMeterProvider when reporting DB stats metrics 2026-07-30 11:35:18 +07:00
internal refactor: use reflect.Pointer instead of reflect.Ptr (#1426) 2026-08-21 16:07:50 +08:00
migrate fix: correct typos in code comments 2026-07-17 17:44:22 +03:00
schema refactor: use reflect.Pointer instead of reflect.Ptr (#1426) 2026-08-21 16:07:50 +08:00
scripts ci: use find replace hardcode when modify func Version 2024-11-21 15:17:06 +08:00
.gitignore call 911 (#912) 2023-10-01 15:10:55 +03:00
.prettierrc.yml chore: format changelog 2021-10-19 16:43:41 +03:00
bun.go fix: correct error message prefix and error type 2026-03-20 14:17:43 +08:00
CHANGELOG.md chore: release v1.2.18 (release.sh) (#1341) 2026-02-28 13:06:26 +02:00
commitlint.config.js chore: add commitlint 2021-09-11 10:21:19 +03:00
CONTRIBUTING.md fix: replace the link to docs repo in CONTRIBUTING.md 2024-12-23 10:57:47 +09:00
db.go fix(db): propagate transaction context into RunInTx callback (#1381) 2026-05-19 15:15:22 +03:00
go.mod chore: release v1.2.17 (release.sh) (#1333) 2026-02-21 14:03:30 +02:00
go.sum chore: release v1.2.17 (release.sh) (#1333) 2026-02-21 14:03:30 +02:00
hook.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
LICENSE Setup GitHub actions 2021-05-06 11:47:11 +03:00
list_tuple_test.go fix: handle []byte and [N]byte in Tuple, separate List from Tuple imp… (#1340) 2026-02-28 12:32:19 +02:00
Makefile test: enable race test (#1265) 2025-08-26 21:13:21 +08:00
model.go refactor: use reflect.Pointer instead of reflect.Ptr (#1426) 2026-08-21 16:07:50 +08:00
model_map.go chore: rename Formatter to QueryGen (internal API) (#1253) 2025-08-09 18:23:09 +03:00
model_map_slice.go chore: rename Formatter to QueryGen (internal API) (#1253) 2025-08-09 18:23:09 +03:00
model_scan.go chore: remove duplicate code (#1251) 2025-08-09 17:25:31 +03:00
model_slice.go chore: remove duplicate code (#1251) 2025-08-09 17:25:31 +03:00
model_table_has_many.go fix(relation): do not duplicate joined models on a shared base model 2026-07-30 11:36:29 +07:00
model_table_m2m.go chore: remove duplicate code (#1251) 2025-08-09 17:25:31 +03:00
model_table_slice.go refactor: use reflect.Pointer instead of reflect.Ptr (#1426) 2026-08-21 16:07:50 +08:00
model_table_struct.go refactor: use reflect.Pointer instead of reflect.Ptr (#1426) 2026-08-21 16:07:50 +08:00
package.json chore: release v1.2.18 (release.sh) (#1341) 2026-02-28 13:06:26 +02:00
query_base.go Merge pull request #1347 from CyJaySong/fix-1321 2026-08-12 19:14:11 +08:00
query_column_add.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
query_column_drop.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
query_delete.go Merge pull request #1347 from CyJaySong/fix-1321 2026-08-12 19:14:11 +08:00
query_index_create.go feat: create unique index on migration name column in Migrator.Init (#1332) 2026-02-21 13:29:53 +02:00
query_index_drop.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
query_insert.go docs: add GoDoc comments to query_insert.go exported API (#1377) 2026-05-19 14:41:49 +03:00
query_merge.go fix: RunMigration marks migration as applied after running (#1330) 2026-02-21 12:21:10 +02:00
query_raw.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
query_select.go Merge remote-tracking branch 'origin/master' into fix/select-clone-execution-state 2026-08-12 19:23:53 +03:00
query_select_clone_test.go fix: copy execution state in SelectQuery.Clone 2026-07-20 16:45:03 +03:00
query_table_create.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
query_table_drop.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
query_table_truncate.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
query_update.go Merge pull request #1347 from CyJaySong/fix-1321 2026-08-12 19:14:11 +08:00
query_values.go chore: add documentation for public API using LLM (#1304) 2025-11-22 10:49:28 +02:00
README.md chore: improve readme 2025-08-09 18:30:03 +03:00
relation_join.go refactor: remove unused relationJoin.Select method 2026-03-20 14:07:04 +08:00
util.go refactor: use reflect.Pointer instead of reflect.Ptr (#1426) 2026-08-21 16:07:50 +08:00
util_test.go fix: comment string zero bytes filtering 2024-12-09 23:50:22 +02:00
version.go chore: release v1.2.18 (release.sh) (#1341) 2026-02-28 13:06:26 +02:00

Bun: SQL-first Golang ORM

build workflow PkgGoDev Documentation Chat Gurubase

Lightweight, SQL-first Golang ORM for PostgreSQL, MySQL, MSSQL, SQLite, and Oracle

Bun is a modern ORM that embraces SQL rather than hiding it. Write complex queries in Go with type safety, powerful scanning capabilities, and database-agnostic code that works across multiple SQL databases.

Key Features

  • SQL-first approach - Write elegant, readable queries that feel like SQL
  • Multi-database support - PostgreSQL, MySQL/MariaDB, MSSQL, SQLite, and Oracle
  • Type-safe operations - Leverage Go's static typing for compile-time safety
  • Flexible scanning - Query results into structs, maps, scalars, or slices
  • Performance optimized - Built on database/sql with minimal overhead
  • Rich relationships - Define complex table relationships with struct tags
  • Production ready - Migrations, fixtures, soft deletes, and OpenTelemetry support

🚀 Quick Start

go get github.com/uptrace/bun

Basic Example

package main

import (
    "context"
    "database/sql"
    "fmt"

    "github.com/uptrace/bun"
    "github.com/uptrace/bun/dialect/sqlitedialect"
    "github.com/uptrace/bun/driver/sqliteshim"
)

func main() {
    ctx := context.Background()

    // Open database
    sqldb, err := sql.Open(sqliteshim.ShimName, "file::memory:")
    if err != nil {
        panic(err)
    }

    // Create Bun instance
    db := bun.NewDB(sqldb, sqlitedialect.New())

    // Define model
    type User struct {
        ID   int64  `bun:",pk,autoincrement"`
        Name string `bun:",notnull"`
    }

    // Create table
    db.NewCreateTable().Model((*User)(nil)).Exec(ctx)

    // Insert user
    user := &User{Name: "John Doe"}
    db.NewInsert().Model(user).Exec(ctx)

    // Query user
    err = db.NewSelect().Model(user).Where("id = ?", user.ID).Scan(ctx)
    fmt.Printf("User: %+v\n", user)
}

🎯 Why Choose Bun?

Elegant Complex Queries

Write sophisticated queries that remain readable and maintainable:

regionalSales := db.NewSelect().
    ColumnExpr("region").
    ColumnExpr("SUM(amount) AS total_sales").
    TableExpr("orders").
    GroupExpr("region")

topRegions := db.NewSelect().
    ColumnExpr("region").
    TableExpr("regional_sales").
    Where("total_sales > (SELECT SUM(total_sales) / 10 FROM regional_sales)")

var results []struct {
    Region       string `bun:"region"`
    Product      string `bun:"product"`
    ProductUnits int    `bun:"product_units"`
    ProductSales int    `bun:"product_sales"`
}

err := db.NewSelect().
    With("regional_sales", regionalSales).
    With("top_regions", topRegions).
    ColumnExpr("region, product").
    ColumnExpr("SUM(quantity) AS product_units").
    ColumnExpr("SUM(amount) AS product_sales").
    TableExpr("orders").
    Where("region IN (SELECT region FROM top_regions)").
    GroupExpr("region, product").
    Scan(ctx, &results)

Flexible Result Scanning

Scan query results into various Go types:

// Into structs
var users []User
db.NewSelect().Model(&users).Scan(ctx)

// Into maps
var userMaps []map[string]interface{}
db.NewSelect().Table("users").Scan(ctx, &userMaps)

// Into scalars
var count int
db.NewSelect().Table("users").ColumnExpr("COUNT(*)").Scan(ctx, &count)

// Into individual variables
var id int64
var name string
db.NewSelect().Table("users").Column("id", "name").Limit(1).Scan(ctx, &id, &name)

📊 Database Support

Database Driver Dialect
PostgreSQL github.com/uptrace/bun/driver/pgdriver pgdialect.New()
MySQL/MariaDB github.com/go-sql-driver/mysql mysqldialect.New()
SQLite github.com/uptrace/bun/driver/sqliteshim sqlitedialect.New()
SQL Server github.com/denisenkom/go-mssqldb mssqldialect.New()
Oracle github.com/sijms/go-ora/v2 oracledialect.New()

🔧 Advanced Features

Table Relationships

Define complex relationships with struct tags:

type User struct {
    ID      int64   `bun:",pk,autoincrement"`
    Name    string  `bun:",notnull"`
    Posts   []Post  `bun:"rel:has-many,join:id=user_id"`
    Profile Profile `bun:"rel:has-one,join:id=user_id"`
}

type Post struct {
    ID     int64 `bun:",pk,autoincrement"`
    Title  string
    UserID int64
    User   *User `bun:"rel:belongs-to,join:user_id=id"`
}

// Load users with their posts
var users []User
err := db.NewSelect().
    Model(&users).
    Relation("Posts").
    Scan(ctx)

Bulk Operations

Efficient bulk operations for large datasets:

// Bulk insert
users := []User{{Name: "John"}, {Name: "Jane"}, {Name: "Bob"}}
_, err := db.NewInsert().Model(&users).Exec(ctx)

// Bulk update with CTE
_, err = db.NewUpdate().
    Model(&users).
    Set("updated_at = NOW()").
    Where("active = ?", true).
    Exec(ctx)

// Bulk delete
_, err = db.NewDelete().
    Model((*User)(nil)).
    Where("created_at < ?", time.Now().AddDate(-1, 0, 0)).
    Exec(ctx)

Migrations

Version your database schema:

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

migrations := migrate.NewMigrations()

migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
    _, err := db.NewCreateTable().Model((*User)(nil)).Exec(ctx)
    return err
}, func(ctx context.Context, db *bun.DB) error {
    _, err := db.NewDropTable().Model((*User)(nil)).Exec(ctx)
    return err
})

migrator := migrate.NewMigrator(db, migrations)
err := migrator.Init(ctx)
err = migrator.Up(ctx)

📈 Monitoring & Observability

Debug Queries

Enable query logging for development:

import "github.com/uptrace/bun/extra/bundebug"

db.AddQueryHook(bundebug.NewQueryHook(
    bundebug.WithVerbose(true),
))

OpenTelemetry Integration

Production-ready observability with distributed tracing:

import "github.com/uptrace/bun/extra/bunotel"

db.AddQueryHook(bunotel.NewQueryHook(
    bunotel.WithDBName("myapp"),
))

Monitoring made easy: Bun is brought to you by uptrace/uptrace. Uptrace is an open-source APM tool that supports distributed tracing, metrics, and logs. You can use it to monitor applications and set up automatic alerts to receive notifications via email, Slack, Telegram, and others.

See OpenTelemetry example which demonstrates how you can use Uptrace to monitor Bun.

📚 Documentation & Resources

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details on how to get started.

Thanks to all our contributors:

Contributors
Star this repo if you find Bun useful!
Join our community on Discord • Follow updates on GitHub