Introduction
GORM is the standard ORM for Go applications. It maps Go structs to database tables and provides a chainable API for CRUD operations, associations, transactions, and migrations. Despite Go's preference for simplicity, GORM fills the gap for developers who want ActiveRecord/Django ORM-style productivity.
With over 40,000 GitHub stars, GORM is used in production by thousands of Go applications. GORM v2 brought significant improvements including a plugin system, better performance, and support for context, batch operations, and prepared statements.
What GORM Does
GORM translates Go struct operations into SQL queries. Define your models as Go structs with tags, and GORM handles table creation (auto-migration), CRUD operations, associations (has-one, has-many, many-to-many), transactions, hooks (callbacks), and raw SQL when needed.
Architecture Overview
[Go Structs (Models)]
type User struct {
gorm.Model
Name string
Posts []Post
}
|
[GORM API]
db.Create(), db.Find(),
db.Update(), db.Delete()
Chainable query builder
|
[GORM Core]
SQL generation
Association handling
Hook/callback system
Transaction management
|
[Database Drivers]
+-------+-------+-------+
| | | |
[Postgres] [MySQL] [SQLite] [SQL Server]
gorm.io/ gorm.io/ gorm.io/ gorm.io/
driver/ driver/ driver/ driver/
postgres mysql sqlite sqlserverSelf-Hosting & Configuration
import (
"gorm.io/gorm"
"gorm.io/driver/postgres"
"log"
)
// Models with associations
type User struct {
gorm.Model
Name string `gorm:"size:100;not null"`
Email string `gorm:"uniqueIndex"`
Posts []Post
Profile Profile
}
type Post struct {
gorm.Model
Title string
Body string
UserID uint
Tags []Tag `gorm:"many2many:post_tags;"`
}
type Profile struct {
gorm.Model
UserID uint
Bio string
}
type Tag struct {
gorm.Model
Name string `gorm:"uniqueIndex"`
}
func main() {
dsn := "host=localhost user=postgres password=secret dbname=myapp port=5432"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
// Auto-migrate all models
db.AutoMigrate(&User{}, &Post{}, &Profile{}, &Tag{})
// Create with associations
db.Create(&User{
Name: "Alice",
Email: "alice@example.com",
Posts: []Post{
{Title: "First Post", Body: "Hello World"},
},
Profile: Profile{Bio: "Go developer"},
})
// Query with preloading
var users []User
db.Preload("Posts").Preload("Profile").Find(&users)
// Complex query
var results []User
db.Where("age > ?", 18).
Order("created_at desc").
Limit(10).
Find(&results)
// Transaction
db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&User{Name: "Bob"}).Error; err != nil {
return err
}
return tx.Create(&Post{Title: "New", UserID: 1}).Error
})
}Key Features
- Auto-Migration — create and update tables from Go struct definitions
- Associations — has-one, has-many, many-to-many, polymorphic
- Hooks — BeforeCreate, AfterUpdate, BeforeDelete callbacks
- Transactions — nested transactions with savepoints
- Preloading — eager loading of associations
- Batch Operations — batch insert, update, and upsert
- Raw SQL — execute raw SQL when ORM is not enough
- Plugin System — extend with custom plugins (soft delete, sharding, etc.)
Comparison with Similar Tools
| Feature | GORM | Ent | sqlx | sqlc | XORM |
|---|---|---|---|---|---|
| Type | Full ORM | Code-gen ORM | SQL helper | Code-gen SQL | Full ORM |
| Approach | Runtime reflection | Code generation | Raw SQL | Raw SQL | Runtime reflection |
| Associations | Built-in | Built-in | Manual | Manual | Built-in |
| Migration | Auto-migrate | Code-gen | Manual | Manual | Auto-sync |
| Type Safety | Moderate | Excellent | Good | Excellent | Moderate |
| Performance | Good | Very Good | Excellent | Excellent | Good |
| Learning Curve | Low | Moderate | Low | Low | Low |
FAQ
Q: GORM vs sqlx — which should I use? A: GORM for rapid development with auto-migration, associations, and hooks. sqlx for maximum control, performance, and when you prefer writing SQL directly. Many teams use GORM for CRUD-heavy apps and sqlx for performance-critical queries.
Q: Is GORM performant enough for production? A: Yes. GORM v2 includes prepared statement caching, batch operations, and efficient query building. For hot paths, use raw SQL via db.Raw() or switch to sqlx for specific queries.
Q: How do I handle soft deletes? A: GORM has built-in soft delete via gorm.Model (includes DeletedAt field). Queries automatically filter soft-deleted records. Use db.Unscoped() to include them.
Q: Can I use GORM with multiple databases? A: Yes. Create separate gorm.DB instances for each database. GORM also supports read/write splitting via the DBResolver plugin.
Sources
- GitHub: https://github.com/go-gorm/gorm
- Documentation: https://gorm.io/docs
- Created by Jinzhu Zhang
- License: MIT