Beego ORM
Beego ORM is "an ORM that enhances Go application productivity with Django-like APIs" developed as a core component of the popular Beego web framework in the Go ecosystem. With intuitive API design inspired by Django and SQLAlchemy, it simplifies database operations through a Code First approach. Supporting MySQL, PostgreSQL, and SQLite3, it efficiently handles complex query operations and relationship management while maintaining type safety.
GitHub Overview
beego/beego
beego is an open-source, high-performance web framework for the Go programming language.
Topics
Star History
Library
Beego ORM
Overview
Beego ORM is "an ORM that enhances Go application productivity with Django-like APIs" developed as a core component of the popular Beego web framework in the Go ecosystem. With intuitive API design inspired by Django and SQLAlchemy, it simplifies database operations through a Code First approach. Supporting MySQL, PostgreSQL, and SQLite3, it efficiently handles complex query operations and relationship management while maintaining type safety.
Details
Beego ORM 2025 edition has established itself as the standard database layer solution for enterprise-level web application development in Go. It provides comprehensive features including struct-based model definitions, automatic table creation, query generation, and transaction management. Tightly integrated with Go's type system, it minimizes runtime errors through compile-time type checking. Leveraging reflection and code generation, it automatically maps Go structs to database tables, enabling the construction of highly maintainable data access layers.
Key Features
- Code First Approach: Automatic database table generation from Go struct definitions
- Rich Database Support: Comprehensive support for MySQL, PostgreSQL, and SQLite3
- Type-Safe Queries: Safe database operations leveraging Go's type system
- Automatic Join Functionality: Automatic join query generation for related tables
- Raw SQL Support: Plain SQL execution capabilities for complex queries
- Transaction Management: Transaction functionality with automatic commit/rollback
Pros and Cons
Pros
- High type safety through excellent integration with Go's standard type system
- Reduced learning costs and improved development efficiency with Django-like APIs
- Rapid prototyping and schema management through automatic table creation features
- Flexible database operations through rich query builder functionality
- Consistent development experience through complete integration with Beego framework
- Improved maintainability through reflection-based automatic mapping
Cons
- Performance constraints due to reflection overhead when processing large amounts of data
- ORM-specific error handling that differs from Go's conventional error handling
- Limitations in expressing complex SQL queries requiring Raw SQL in some cases
- Manual management required for schema migration when model structures change
- Limited access to database-specific optimization features
- High integration costs when used outside the Beego framework
Reference Pages
Code Examples
Basic Setup
package main
import (
"github.com/beego/beego/v2/client/orm"
_ "github.com/go-sql-driver/mysql" // MySQL driver
_ "github.com/lib/pq" // PostgreSQL driver
_ "github.com/mattn/go-sqlite3" // SQLite3 driver
)
func init() {
// Register database
orm.RegisterDataBase("default", "mysql",
"user:password@tcp(localhost:3306)/database?charset=utf8mb4&parseTime=True&loc=Local", 30)
// For PostgreSQL
// orm.RegisterDataBase("default", "postgres",
// "host=localhost port=5432 user=postgres password=password dbname=mydb sslmode=disable")
// For SQLite3
// orm.RegisterDataBase("default", "sqlite3", "path/to/database.db")
// Register models
orm.RegisterModel(new(User), new(Profile), new(Post))
// Auto-create tables (development only)
orm.RunSyncdb("default", false, true)
}
func main() {
// Get ORM instance
o := orm.NewOrm()
// Basic usage example
user := &User{Name: "John Doe", Email: "[email protected]"}
id, err := o.Insert(user)
if err != nil {
panic(err)
}
fmt.Printf("User created with ID: %d\n", id)
}
Model Definition and Basic Operations
package models
import (
"time"
"github.com/beego/beego/v2/client/orm"
)
// User model
type User struct {
Id int `orm:"auto"` // Auto-increment primary key
Name string `orm:"size(100)"` // String length limit
Email string `orm:"unique"` // Unique constraint
Age int `orm:"null"` // Allow NULL
IsActive bool `orm:"default(true)"` // Default value
Created time.Time `orm:"auto_now_add;type(datetime)"` // Auto-set on creation
Updated time.Time `orm:"auto_now;type(datetime)"` // Auto-set on update
// Relationships
Profile *Profile `orm:"rel(one)"` // One-to-one relationship
Posts []*Post `orm:"reverse(many)"` // One-to-many relationship (reverse)
}
// Profile model
type Profile struct {
Id int `orm:"auto"`
Bio string `orm:"type(text);null"`
User *User `orm:"reverse(one)"` // Reverse one-to-one
}
// Post model
type Post struct {
Id int `orm:"auto"`
Title string `orm:"size(200)"`
Content string `orm:"type(text)"`
Published bool `orm:"default(false)"`
Created time.Time `orm:"auto_now_add;type(datetime)"`
User *User `orm:"rel(fk)"` // Foreign key
}
// Custom table name
func (u *User) TableName() string {
return "users"
}
// CRUD operations implementation
func CreateUser(name, email string, age int) (*User, error) {
o := orm.NewOrm()
user := &User{
Name: name,
Email: email,
Age: age,
}
// Insert operation
id, err := o.Insert(user)
if err != nil {
return nil, err
}
user.Id = int(id)
return user, nil
}
func GetUserByID(id int) (*User, error) {
o := orm.NewOrm()
user := &User{Id: id}
err := o.Read(user)
if err != nil {
return nil, err
}
return user, nil
}
func GetUserByEmail(email string) (*User, error) {
o := orm.NewOrm()
user := &User{}
err := o.QueryTable("user").Filter("email", email).One(user)
if err != nil {
return nil, err
}
return user, nil
}
func UpdateUser(user *User) error {
o := orm.NewOrm()
_, err := o.Update(user)
return err
}
func DeleteUser(id int) error {
o := orm.NewOrm()
user := &User{Id: id}
_, err := o.Delete(user)
return err
}
// Validation (custom implementation)
func (u *User) Valid() error {
if len(u.Name) < 2 {
return fmt.Errorf("name must be at least 2 characters")
}
if !strings.Contains(u.Email, "@") {
return fmt.Errorf("invalid email format")
}
if u.Age < 0 || u.Age > 150 {
return fmt.Errorf("age must be between 0 and 150")
}
return nil
}
Advanced Query Operations
package services
import (
"fmt"
"github.com/beego/beego/v2/client/orm"
)
// Complex query operations
func GetUsersWithConditions(minAge, maxAge int, namePattern string) ([]*User, error) {
o := orm.NewOrm()
var users []*User
qs := o.QueryTable("user")
// Filter by age range
if minAge > 0 {
qs = qs.Filter("age__gte", minAge)
}
if maxAge > 0 {
qs = qs.Filter("age__lte", maxAge)
}
// Partial name match
if namePattern != "" {
qs = qs.Filter("name__icontains", namePattern)
}
// Active users only
qs = qs.Filter("is_active", true)
// Sort
qs = qs.OrderBy("-created")
// Get results
_, err := qs.All(&users)
if err != nil {
return nil, err
}
return users, nil
}
// Aggregate queries
func GetUserStatistics() (map[string]interface{}, error) {
o := orm.NewOrm()
stats := make(map[string]interface{})
// Total users
totalUsers, err := o.QueryTable("user").Count()
if err != nil {
return nil, err
}
stats["total_users"] = totalUsers
// Active users
activeUsers, err := o.QueryTable("user").Filter("is_active", true).Count()
if err != nil {
return nil, err
}
stats["active_users"] = activeUsers
// Average age (using Raw SQL)
var avgAge float64
err = o.Raw("SELECT AVG(age) FROM users WHERE age > 0").QueryRow(&avgAge)
if err != nil {
return nil, err
}
stats["average_age"] = avgAge
return stats, nil
}
// Fetch with relations
func GetUserWithProfile(userID int) (*User, error) {
o := orm.NewOrm()
user := &User{Id: userID}
err := o.Read(user)
if err != nil {
return nil, err
}
// Load profile information
_, err = o.LoadRelated(user, "Profile")
if err != nil {
return nil, err
}
return user, nil
}
func GetUsersWithPosts() ([]*User, error) {
o := orm.NewOrm()
var users []*User
// Fetch users and posts together
_, err := o.QueryTable("user").RelatedSel().All(&users)
if err != nil {
return nil, err
}
// Load posts for each user
for _, user := range users {
_, err = o.LoadRelated(user, "Posts")
if err != nil {
return nil, err
}
}
return users, nil
}
// Conditional updates
func UpdateUsersStatus(condition map[string]interface{}, status bool) (int64, error) {
o := orm.NewOrm()
qs := o.QueryTable("user")
// Apply dynamic conditions
for key, value := range condition {
qs = qs.Filter(key, value)
}
// Bulk update
return qs.Update(orm.Params{
"is_active": status,
"updated": time.Now(),
})
}
// Pagination
func GetUsersPaginated(page, pageSize int) ([]*User, int64, error) {
o := orm.NewOrm()
var users []*User
qs := o.QueryTable("user").Filter("is_active", true).OrderBy("-created")
// Get total count
total, err := qs.Count()
if err != nil {
return nil, 0, err
}
// Apply pagination
offset := (page - 1) * pageSize
_, err = qs.Limit(pageSize, offset).All(&users)
if err != nil {
return nil, 0, err
}
return users, total, nil
}
Relationship Operations
// One-to-one relationship operations
func CreateUserWithProfile(name, email, bio string) (*User, error) {
o := orm.NewOrm()
// Begin transaction
err := o.Begin()
if err != nil {
return nil, err
}
// Create user
user := &User{
Name: name,
Email: email,
}
id, err := o.Insert(user)
if err != nil {
o.Rollback()
return nil, err
}
user.Id = int(id)
// Create profile
profile := &Profile{
Bio: bio,
User: user,
}
_, err = o.Insert(profile)
if err != nil {
o.Rollback()
return nil, err
}
// Commit
err = o.Commit()
if err != nil {
return nil, err
}
user.Profile = profile
return user, nil
}
// One-to-many relationship operations
func CreatePostForUser(userID int, title, content string) (*Post, error) {
o := orm.NewOrm()
// Check user existence
user := &User{Id: userID}
err := o.Read(user)
if err != nil {
return nil, fmt.Errorf("user not found: %v", err)
}
// Create post
post := &Post{
Title: title,
Content: content,
User: user,
}
id, err := o.Insert(post)
if err != nil {
return nil, err
}
post.Id = int(id)
return post, nil
}
// Join operations
func GetPostsWithUserInfo() ([]map[string]interface{}, error) {
o := orm.NewOrm()
var maps []orm.Params
// Join query
_, err := o.Raw(`
SELECT p.id, p.title, p.content, p.published, p.created,
u.name as user_name, u.email as user_email
FROM posts p
INNER JOIN users u ON p.user_id = u.id
WHERE p.published = ?
ORDER BY p.created DESC
`, true).Values(&maps)
if err != nil {
return nil, err
}
// Convert to map[string]interface{}
results := make([]map[string]interface{}, len(maps))
for i, m := range maps {
results[i] = make(map[string]interface{})
for k, v := range m {
results[i][k] = v
}
}
return results, nil
}
Practical Examples
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/server/web"
)
// Controller implementation
type UserController struct {
web.Controller
}
// GET /users - Get user list
func (c *UserController) GetAll() {
page, _ := strconv.Atoi(c.GetString("page", "1"))
pageSize, _ := strconv.Atoi(c.GetString("page_size", "10"))
users, total, err := GetUsersPaginated(page, pageSize)
if err != nil {
c.Data["json"] = map[string]interface{}{
"error": err.Error(),
}
c.Ctx.ResponseWriter.WriteHeader(http.StatusInternalServerError)
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{
"users": users,
"total": total,
"page": page,
"page_size": pageSize,
}
c.ServeJSON()
}
// GET /users/:id - Get user details
func (c *UserController) Get() {
idStr := c.Ctx.Input.Param(":id")
id, err := strconv.Atoi(idStr)
if err != nil {
c.Data["json"] = map[string]interface{}{
"error": "Invalid user ID",
}
c.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest)
c.ServeJSON()
return
}
user, err := GetUserWithProfile(id)
if err != nil {
c.Data["json"] = map[string]interface{}{
"error": "User not found",
}
c.Ctx.ResponseWriter.WriteHeader(http.StatusNotFound)
c.ServeJSON()
return
}
c.Data["json"] = user
c.ServeJSON()
}
// POST /users - Create user
func (c *UserController) Post() {
var userRequest struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
Bio string `json:"bio"`
}
err := json.Unmarshal(c.Ctx.Input.RequestBody, &userRequest)
if err != nil {
c.Data["json"] = map[string]interface{}{
"error": "Invalid JSON format",
}
c.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest)
c.ServeJSON()
return
}
// Validation
if userRequest.Name == "" || userRequest.Email == "" {
c.Data["json"] = map[string]interface{}{
"error": "Name and email are required",
}
c.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest)
c.ServeJSON()
return
}
// Create user
user, err := CreateUserWithProfile(userRequest.Name, userRequest.Email, userRequest.Bio)
if err != nil {
c.Data["json"] = map[string]interface{}{
"error": err.Error(),
}
c.Ctx.ResponseWriter.WriteHeader(http.StatusInternalServerError)
c.ServeJSON()
return
}
c.Data["json"] = user
c.Ctx.ResponseWriter.WriteHeader(http.StatusCreated)
c.ServeJSON()
}
// Database initialization
func InitDatabase() {
// Create test data for development environment
o := orm.NewOrm()
// Create sample users
users := []*User{
{Name: "Alice Johnson", Email: "[email protected]", Age: 28},
{Name: "Bob Smith", Email: "[email protected]", Age: 35},
{Name: "Carol Brown", Email: "[email protected]", Age: 22},
}
for _, user := range users {
_, err := o.Insert(user)
if err != nil {
log.Printf("Failed to create user %s: %v", user.Name, err)
} else {
log.Printf("Created user: %s", user.Name)
}
}
}
// Main function
func main() {
// Routing configuration
web.Router("/users", &UserController{}, "get:GetAll;post:Post")
web.Router("/users/:id", &UserController{}, "get:Get")
// Initialize database
InitDatabase()
log.Println("Server starting on :8080")
web.Run(":8080")
}