bun is a free, open source databases project written in Go and released under BSD-2-Clause. It has 4,976 GitHub stars, 307 forks and 38 open issues, and was last pushed 28 days ago. On this registry it ranks #147 of 203 tracked projects in Databases, with 5 head-to-head comparisons available.

What is bun?

Bun is a lightweight, SQL-first object-relational mapper for Go that gives backend engineers type-safe access to PostgreSQL, MySQL/MariaDB, MSSQL, SQLite, and Oracle from one database-agnostic codebase.

What it is

Bun is an ORM library for the Go ecosystem, published as github.com/uptrace/bun and built on top of the standard library's database/sql package with minimal overhead. Rather than hiding SQL behind an abstraction, it embraces SQL: queries are written with chainable builders such as db.NewSelect(), db.NewInsert(), and db.NewCreateTable(), and the library's dialects translate them for each supported database. A bun.NewDB instance pairs a *sql.DB handle with a dialect, for example sqlitedialect.New() or pgdialect.New().

The concrete problem it solves is the boilerplate and dialect drift that appear when a Go service talks to more than one SQL database. Without it, teams hand-write query strings, write separate SQL for PostgreSQL, MySQL, MSSQL, SQLite, and Oracle, and write repetitive scanning code to move rows into structs. Bun replaces that hand-rolled layer with a single typed query API, dialect-aware drivers, and result scanning that targets structs, maps, or scalars. The project carries the BSD-2-Clause licence and sits in the Infrastructure & Operations / Databases category, with 4,976 stars, 307 forks, and 38 open issues at the time of the recorded push.

Key capabilities

  • SQL-first query builders: db.NewSelect(), db.NewInsert(), ColumnExpr, TableExpr, GroupExpr, and Where("id = ?", ...) with bound parameters.
  • Common table expressions through .With("regional_sales", regionalSales) and .With("top_regions", topRegions) for multi-step analytical queries.
  • Multi-database support across PostgreSQL, MySQL/MariaDB, MSSQL, SQLite, and Oracle, with dialects including pgdialect.New(), mysqldialect.New(), sqlitedialect.New(), and mssqldialect.New().
  • Matching drivers, including github.com/uptrace/bun/driver/pgdriver, github.com/go-sql-driver/mysql, github.com/uptrace/bun/driver/sqliteshim, and github.com/denisenkom/go-mssqldb.
  • Type-safe models declared with bun struct tags such as bun:",pk,autoincrement" and bun:",notnull", including table creation via db.NewCreateTable().Model((*User)(nil)).
  • Flexible scanning of results into structs, maps, slices, scalars, or individual variables.
  • Production features: migrations, fixtures, soft deletes, and OpenTelemetry support.

Who uses it and how

  • Go teams that run PostgreSQL in production while testing against SQLite or an in-memory file::memory: database, keeping one query implementation for both.
  • Services that need complex reporting queries, such as grouped regional sales with subquery filters, without dropping to raw SQL strings.
  • Applications with evolving schemas that use Bun migrations and fixtures to move schema and seed data alongside the code.
  • Systems that rely on soft deletes rather than physically removing rows.
  • Shops with observability requirements that wire OpenTelemetry through the database layer.

Getting started

Install with go get github.com/uptrace/bun, then add the dialect and driver packages for the target database, for example sqliteshim.ShimName with sqlitedialect.New(). Documentation lives at https://bun.uptrace.dev, with a Discord chat and a Gurubase "Ask Bun Guru" assistant linked from the repository.

How it compares

No competing or paid products are named in the facts recorded for this entry, so no licence, hosting, or cost comparison can be drawn. Among the tools named in this registry, Bun stands alone.

When to use it — and when not to

Bun is a library, not a service: the operator still provisions and runs the database, handles backups, and manages connection credentials, and there is no hosted option to fall back on. It also assumes fluency in SQL, so a team that wants SQL hidden behind a full abstraction layer will find the SQL-first style working against it rather than for it. The README excerpt ends mid-entry for the Oracle driver, so anyone targeting Oracle should confirm the current driver and dialect names against the documentation before committing.

project readme (upstream, from github) — read inline

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

🔗 Related Projects


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

Frequently asked questions

Is bun free to use?

bun is open source under the BSD-2-Clause licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does bun do?

SQL-first Golang ORM

What is bun written in?

bun is primarily written in Go. Its source is publicly available at https://github.com/uptrace/bun, and it has 4,976 GitHub stars.