ORM for Go (Golang): comparison and examples
When developing in Go (Golang), working with databases is one of the key tasks. Unlike many dynamic languages, Go does not have a built-in ORM (Object-Relational Mapping), but the community has created several powerful libraries. In this article, we will compare three popular approaches in detail: GORM, Ent, and sqlx. You will learn their strengths and weaknesses, and see code examples for each library.
Why do you need an ORM in Go?
An ORM simplifies interaction with relational databases by allowing you to work with tables as regular Go structs. The main advantages are:
- Automatic generation of SQL queries
- Database schema migrations
- Protection against SQL injections
- Faster development
However, an ORM can reduce performance on complex queries and hide SQL details, which is critical for high-load projects.
1. GORM — the most popular ORM for Go
GORM is a full-featured ORM with an active community (over 35k stars on GitHub). It provides a rich API for CRUD operations, migrations, hooks, and relationships.
Example of working with GORM
Let's define a model and perform simple operations:
package main
import ( "gorm.io/driver/sqlite" "gorm.io/gorm")
type User struct { ID uint `gorm:"primaryKey"` Name string Email string `gorm:"uniqueIndex"`}
func main() { db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{}) if err != nil { panic("failed to connect database") }
// Auto-migration db.AutoMigrate(&User{})
// Create db.Create(&User{Name: "Alice", Email: "alice@example.com"})
// Read var user User db.First(&user, 1) // by ID db.First(&user, "email = ?", "alice@example.com")
// Update db.Model(&user).Update("Name", "Alice Updated")
// Delete db.Delete(&user)}Pros of GORM:
- Simple and intuitive API
- Support for relationships (BelongsTo, HasMany, Many2Many)
- Built-in migrations and hooks
- Wide support for DBMS (PostgreSQL, MySQL, SQLite, SQL Server)
Cons:
- Performance degradation on complex queries
- Magical behavior (e.g., automatic field modification)
- Difficulties with custom SQL queries
2. Ent — code-first ORM from Facebook
Ent is an ORM based on code generation. Instead of reflection, as in GORM, Ent generates typed Go code from a schema, which provides high performance and type safety.
Example of working with Ent
First, let's define a schema in the file schema/user.go:
package schema
import ( "entgo.io/ent" "entgo.io/ent/schema/field")
type User struct { ent.Schema}
func (User) Fields() []ent.Field { return []ent.Field{ field.String("name"), field.String("email").Unique(), }}After code generation (command go generate ./...), we use the generated API:
package main
import ( "context" "log"
"your-project/ent" _ "github.com/mattn/go-sqlite3")
func main() { client, err := ent.Open("sqlite3", "file:ent.db?cache=shared&_fk=1") if err != nil { log.Fatal(err) } defer client.Close()
ctx := context.Background()
// Auto-migration if err := client.Schema.Create(ctx); err != nil { log.Fatal(err) }
// Create user user, err := client.User.Create(). SetName("Bob"). SetEmail("bob@example.com"). Save(ctx) if err != ni