Database Connection
In Go, you generally have three layers of abstraction to connect with databases:
| Level | Description | Common Packages |
|---|---|---|
| π§± Low-level | Use database/sql directly (standard lib) | database/sql, driver like lib/pq, mysql, pgx |
| βοΈ Mid-level | Lightweight ORM or query builder | sqlx, squirrel, pgxpool |
| π High-level | Full ORM (models, relations, migrations) | GORM, Ent, Bun, Prisma Go (coming up) |
1. Standard Library: database/sqlβ
Import Driver & Connectβ
import (
"database/sql"
_ "github.com/lib/pq" // PostgreSQL driver
)
dsn := "postgres://user:pass@localhost:5432/mydb?sslmode=disable"
db, err := sql.Open("postgres", dsn)
if err != nil { log.Fatal(err) }
defer db.Close()
Ping & Check Connectionβ
if err := db.Ping(); err != nil {
log.Fatal("DB unreachable:", err)
}
Query Dataβ
rows, err := db.Query("SELECT id, name FROM users WHERE active=$1", true)
defer rows.Close()
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name)
fmt.Println(id, name)
}
Query Single Rowβ
var email string
err := db.QueryRow("SELECT email FROM users WHERE id=$1", 1).Scan(&email)
Exec (INSERT/UPDATE/DELETE)β
res, err := db.Exec("UPDATE users SET name=$1 WHERE id=$2", "Fee Fight", 1)
affected, _ := res.RowsAffected()
Transactionsβ
tx, _ := db.Begin()
_, err := tx.Exec("INSERT INTO logs(message) VALUES($1)", "hello")
if err != nil {
tx.Rollback()
return
}
tx.Commit()
2. Popular Drivers (plug into database/sql)β
| Database | Driver | Import Path |
|---|---|---|
| PostgreSQL | lib/pq or jackc/pgx/stdlib | _ "github.com/lib/pq" or _ "github.com/jackc/pgx/v5/stdlib" |
| MySQL / MariaDB | go-sql-driver/mysql | _ "github.com/go-sql-driver/mysql" |
| SQLite | modernc.org/sqlite (pure Go) | _ "modernc.org/sqlite" |
| SQL Server | denisenkom/go-mssqldb | _ "github.com/denisenkom/go-mssqldb" |
β‘
pgxis increasingly preferred overlib/pqfor Postgres β itβs faster, supports more features, and can be used standalone or withdatabase/sql.
3. sqlx β Upgraded database/sqlβ
https://github.com/jmoiron/sqlx
Adds struct mapping, named queries, and convenience methods.
import "github.com/jmoiron/sqlx"
db, _ := sqlx.Connect("postgres", dsn)
// Named parameters
rows, _ := db.NamedQuery("SELECT * FROM users WHERE age >= :age", map[string]interface{}{"age": 18})
// Struct mapping
type User struct { ID int `db:"id"`; Name string `db:"name"` }
var users []User
db.Select(&users, "SELECT id, name FROM users")
β
Keeps control like database/sql
β
Zero magic
βοΈ Great for microservices or APIs
4. pgx β Native Postgres Driverβ
Faster + more feature-rich (copy, notifications, pools, etc.)
import "github.com/jackc/pgx/v5/pgxpool"
pool, _ := pgxpool.New(context.Background(), dsn)
defer pool.Close()
rows, _ := pool.Query(ctx, "SELECT id, name FROM users")
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name)
}
β Best for PostgreSQL-heavy backends β Built-in connection pool β Fine-grained control (batching, COPY, notifications)
5. GORM β The Most Popular ORMβ
Setupβ
import (
"gorm.io/gorm"
"gorm.io/driver/postgres"
)
dsn := "host=localhost user=me password=pass dbname=mydb sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
Model & Migrateβ
type User struct {
ID uint `gorm:"primaryKey"`
Name string
Email string `gorm:"uniqueIndex"`
}
db.AutoMigrate(&User{})
CRUDβ
db.Create(&User{Name: "Fee", Email: "fee@fight.dev"})
var u User
db.First(&u, "email = ?", "fee@fight.dev")
db.Model(&u).Update("Name", "Fee Fight")
db.Delete(&u)
β ORM (relations, hooks, migrations) β Very active community βοΈ Slightly heavier, but solid for APIs and SaaS apps
6. Ent β Type-Safe ORM (by Facebook)β
Ent generates Go code (schema β Go structs β SQL migrations).
go get entgo.io/ent/cmd/ent
go run entgo.io/ent/cmd/ent init User
Schema example:
// ent/schema/user.go
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
field.String("email").Unique(),
}
}
Generate code:
go generate ./ent
Usage:
client, _ := ent.Open("postgres", dsn)
defer client.Close()
u, _ := client.User.Create().SetName("Fee").SetEmail("fee@fight.dev").Save(ctx)
fmt.Println(u.ID)
β Type-safe queries (compile-time check) β Generates migrations βοΈ Slight learning curve, best for larger apps
7. Bun β Modern ORM (Fast + Familiar)β
Built on pgx, supports PostgreSQL, MySQL, SQLite.
import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/driver/pgdriver"
)
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
db := bun.NewDB(sqldb, pgdialect.New())
type User struct {
ID int64 `bun:",pk,autoincrement"`
Name string
}
db.NewInsert().Model(&User{Name: "Fee"}).Exec(ctx)
β Fast, active, SQL-first ORM β Integrates with metrics/logs easily β Feels like GORM but lighter
8. NoSQL Optionsβ
| Database | Package | Notes |
|---|---|---|
| MongoDB | go.mongodb.org/mongo-driver | Official driver |
| Redis | github.com/redis/go-redis/v9 | Great for caching, pub/sub |
| Cassandra | github.com/gocql/gocql | Mature driver |
| Elasticsearch | github.com/elastic/go-elasticsearch/v8 | Official client |
Example Mongo snippet:
client, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
col := client.Database("test").Collection("users")
col.InsertOne(ctx, bson.M{"name": "Fee"})
9. Connection Poolingβ
-
database/sqlalready pools connections internally. -
pgxpool(for Postgres) gives explicit control. -
Tune with:
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(time.Hour)
10. Migration Toolsβ
| Tool | Command | Description |
|---|---|---|
| golang-migrate | migrate -path db/migrations -database postgres://... up | CLI + Go API |
| goose | Simple, SQL-based migrations | |
| gormigrate | For GORM ORM projects | |
| atlas | Modern schema management for Ent / SQL |
π‘ Recommended Stack (2025)β
| Scale | Stack | Why |
|---|---|---|
| π§© Small API | database/sql + sqlx | Lightweight & fast |
| π Mid-size service | pgx or Bun | Strong performance + dev ergonomics |
| π§ Full app / SaaS | GORM or Ent | Rich ORM + migration system |
| β‘ Data-intensive / custom SQL | pgxpool + query builder | Max control |