Skip to content

goodm

A schema-driven ODM for MongoDB in Go.

Define your models as Go structs, and goodm handles validation, hooks, indexes, immutability, references, middleware, aggregation, bulk operations, and transactions.

type User struct {
    goodm.Model `bson:",inline"`
    Email       string `bson:"email" goodm:"unique,required"`
    Name        string `bson:"name"  goodm:"required,immutable"`
    Age         int    `bson:"age"   goodm:"min=13,max=120"`
    Role        string `bson:"role"  goodm:"enum=admin|user|mod,default=user"`
}

func init() {
    goodm.Register(&User{}, "users")
}

Your struct is the schema. Tags declare constraints, indexes, and references. The ODM enforces them on every write.

Why goodm?

Go has a strong MongoDB driver, but no mature ODM that treats Go structs as the schema contract:

  • Prisma dropped Go support. That door is closed.
  • The official mongo-driver is low-level. You get bson.D and Collection.InsertOne — everything else is left to you.
  • Mongoose proved the pattern. Node.js developers have had schema-as-code with lifecycle hooks, population, and middleware for over a decade. Go deserves the same.

Quick Start

Install

go get github.com/dwoolworth/goodm

CLI (optional):

go install github.com/dwoolworth/goodm/cmd/goodm@latest

Connect and Create

package main

import (
    "context"
    "log"

    "github.com/dwoolworth/goodm"
    "go.mongodb.org/mongo-driver/v2/bson"
)

type User struct {
    goodm.Model `bson:",inline"`
    Email       string `bson:"email" goodm:"unique,required"`
    Name        string `bson:"name"  goodm:"required,immutable"`
    Age         int    `bson:"age"   goodm:"min=13,max=120"`
}

func init() {
    goodm.Register(&User{}, "users")
}

func main() {
    ctx := context.Background()

    db, _ := goodm.Connect(ctx, "mongodb://localhost:27017", "myapp")
    goodm.Enforce(ctx, db)

    // Create
    user := &User{Email: "alice@example.com", Name: "Alice", Age: 30}
    goodm.Create(ctx, user)

    // Read
    found := &User{}
    goodm.FindOne(ctx, bson.D{{Key: "email", Value: "alice@example.com"}}, found)

    // Update
    found.Age = 31
    goodm.Update(ctx, found)

    // Delete
    goodm.Delete(ctx, found)
}

Features

Feature What it does
Schema Tags unique, index[=kind], sparse, ttl, required, immutable, default, enum, min, max, ref
CRUD Create, FindOne, FindByID, Find, FindCursor, Count, Exists, Distinct, Update, UpdateFields, Delete
Atomic FindOneAndUpdate, FindOneAndReplace, FindOneAndDelete with upsert
Raw Operations UpdateOne, DeleteOne, UpdateMany, DeleteMany, NewBulk for direct MongoDB access
Hooks BeforeCreate, AfterCreate, BeforeSave, AfterSave, BeforeDelete, AfterDelete
Validation Automatic on Create/Update: required, enum, min/max, immutable enforcement; Enforce can install the same rules as a $jsonSchema collection validator
Middleware Global and per-model middleware chains wrapping all operations
Population Resolve ref= fields, including refs inside subdocuments and slices, by fetching referenced documents
Aggregation Fluent pipeline builder with Match, Group, Sort, Lookup, and more
Bulk CreateMany and SaveMany with hooks/validation, NewBulk builder, UpdateMany/DeleteMany passthrough
Transactions WithTransaction wraps operations in a MongoDB session transaction
Change Streams Watch delivers typed change events with resume tokens, filtering, and pre-images
CLI goodm discover (introspect DB), goodm migrate (sync indexes), goodm inspect (view schemas)

How does goodm compare?

Feature goodm mongo-driver mgm mongox
Schema-as-struct tags Yes No Partial No
Lifecycle hooks 6 hooks No 3 hooks No
Validation (required, enum, min/max) Yes No No No
Immutable fields Yes No No No
Optimistic concurrency (versioning) Yes No No No
Population (ref resolution) Yes No No No
Aggregation builder Fluent API Manual No No
Middleware (global + per-model) Yes No No No
CLI: discover (DB → Go structs) Yes No No No
CLI: migrate (sync indexes) Yes No No No
Default values Yes No No No
Escape hatches (raw MongoDB) Yes N/A Yes Yes

Requirements

  • Go 1.21+
  • MongoDB 4.0+ (6.0+ recommended; tested against 6.0, 7.0, and 8.0)
  • Replica set required for transactions and change streams

Release Notes

See the release notes for what changed in each version, including behavior changes to watch for when upgrading.

License

MIT