GORM — API Surface#

API types#

Library — GORM has no binary, no server, no HTTP endpoints, no gRPC services, no CLI. Its entire surface is a Go library API consumed by user code importing gorm.io/gorm.


Library API#

Public packages exported for use as a library#

PackageRole
gorm.io/gorm (root)Core library: DB, Config, Session, chainable/finisher methods, plugin/callback hooks
gorm.io/gorm/clauseTyped SQL AST expressions usable directly: Where, Or, And, Not, Select, OrderBy, Limit, OnConflict, etc.
gorm.io/gorm/schemaSchema reflection types and serializer registry (advanced/plugin use)
gorm.io/gorm/loggerLogger interface + default and slog-based implementations
gorm.io/gorm/migratorCommonMigrator base for dialect migration implementations
gorm.io/gorm/callbacksRegisterDefaultCallbacks() called by dialects; individual callback fns (BeforeCreate, Query, etc.) are public for override use

API style#

Fluent method chaining on *DB. All chainable and finisher methods return *DB. Errors are accumulated on db.Error rather than returned from each call. Finisher methods trigger execution; chainable methods are lazy.

// typical usage pattern
var users []User
result := db.Where("age > ?", 18).Order("name").Limit(10).Find(&users)
if result.Error != nil { ... }
// result.RowsAffected is also available

Entry point#

func Open(dialector Dialector, opts ...Option) (*DB, error)

gorm.Open is the single constructor. Dialector is supplied by an external driver package (e.g., gorm.io/driver/postgres). opts accepts *Config or anything implementing the Option interface (Apply(*Config) error + AfterInitialize(*DB) error).


Chainable API (chainable_api.go)#

Methods that add constraints/clauses to the current statement; each returns a new *DB (copy-on-write semantics via clone field):

MethodPurpose
Model(value)Set model type / table inference
Table(name, args...)Explicit table name (supports subqueries)
Distinct(args...)Add DISTINCT
Select(query, args...)Column selection
Omit(columns...)Exclude columns from SELECT/INSERT
MapColumns(m)Remap struct field names to column names
Where(query, args...)Add WHERE condition (string, struct, or map)
Not(query, args...)Add NOT WHERE condition
Or(query, args...)Add OR WHERE condition
Joins(query, args...)LEFT JOIN (string-based)
InnerJoins(query, args...)INNER JOIN (string-based)
Group(name)GROUP BY
Having(query, args...)HAVING
Order(value)ORDER BY
Limit(limit)LIMIT
Offset(offset)OFFSET
Scopes(funcs...)Reusable query fragments (func(*DB) *DB)
Preload(query, args...)Eager-load associations
Attrs(attrs...)Default attributes for FirstOrInit/FirstOrCreate
Assign(attrs...)Always-assign attributes for FirstOrInit/FirstOrCreate
Unscoped()Disable soft-delete filtering
Raw(sql, values...)Raw SQL query (enters raw mode)
Clauses(conds...)Inject typed clause.Expression objects directly

Finisher API (finisher_api.go)#

Methods that execute a database operation:

Create

MethodDescription
Create(value)INSERT single record or slice
CreateInBatches(value, batchSize)INSERT in batches
Save(value)Upsert (CREATE or full UPDATE based on primary key)

Query

MethodDescription
First(dest, conds...)SELECT ORDER BY pk ASC LIMIT 1; returns ErrRecordNotFound if absent
Take(dest, conds...)SELECT LIMIT 1 (no ordering)
Last(dest, conds...)SELECT ORDER BY pk DESC LIMIT 1
Find(dest, conds...)SELECT all matching records
FindInBatches(dest, batchSize, fc)Cursor-style batch retrieval
FirstOrInit(dest, conds...)First or initialise (no save)
FirstOrCreate(dest, conds...)First or INSERT
Pluck(column, dest)SELECT single column into slice
Count(count *int64)SELECT COUNT
Scan(dest)Scan arbitrary results (does not set model)
ScanRows(rows, dest)Scan *sql.Rows manually
Row()Returns raw *sql.Row
Rows()Returns raw *sql.Rows

Update

MethodDescription
Update(column, value)UPDATE single column
Updates(values)UPDATE multiple columns (struct or map)
UpdateColumn(column, value)UPDATE without hooks/time auto-fill
UpdateColumns(values)UPDATE multiple columns without hooks

Delete

MethodDescription
Delete(value, conds...)DELETE (soft-delete if model has DeletedAt)

Raw / Exec

MethodDescription
Exec(sql, values...)Raw SQL DML execution

Transactions

MethodDescription
Transaction(fc, opts...)Block-scoped transaction with automatic commit/rollback
Begin(opts...)Manual BEGIN
Commit()Manual COMMIT
Rollback()Manual ROLLBACK
SavePoint(name)SAVEPOINT
RollbackTo(name)ROLLBACK TO SAVEPOINT
Connection(fc)Dedicated connection scope

Session / utility methods (gorm.go)#

MethodDescription
Session(config *Session)Clone DB with per-session overrides (DryRun, PrepareStmt, SkipHooks, etc.)
WithContext(ctx)Sugar over Session(&Session{Context: ctx})
Debug()Sugar over Session(&Session{Logger: info-level logger})
Set(key, value)Store arbitrary value on Statement (visible to callbacks)
Get(key)Retrieve value from Statement
InstanceSet(key, value)Store value on DB instance (shared across clones)
InstanceGet(key)Retrieve instance-level value
AddError(err)Append an error to db.Error
DB()Unwrap underlying *sql.DB
ToSQL(queryFn)DryRun helper — return SQL string without executing
SetupJoinTable(model, field, joinTable)Register a custom join table model
Use(plugin)Register and initialize a Plugin
Callback()Return *callbacks for hook registration

Association API (association.go)#

Accessed via db.Association("FieldName"):

MethodDescription
Find(out, conds...)Query associated records
Append(values...)Append to association (adds FK / join row)
Replace(values...)Replace all association records
Delete(values...)Delete from association
Clear()Remove all associations
Count()Count associated records
Unscoped()Disable soft-delete scoping

Migration API (Migrator interface, migrator.go:68)#

Accessed via db.Migrator(). The dialect implements this interface; db.AutoMigrate(dst...) is the common shortcut.

Key method groups:

  • Tables: CreateTable, DropTable, HasTable, RenameTable, GetTables, TableType
  • Columns: AddColumn, DropColumn, AlterColumn, MigrateColumn, HasColumn, RenameColumn, ColumnTypes
  • Indexes: CreateIndex, DropIndex, HasIndex, RenameIndex, GetIndexes
  • Constraints: CreateConstraint, DropConstraint, HasConstraint
  • Views: CreateView, DropView
  • Misc: CurrentDatabase, FullDataTypeOf, GetTypeAliases

Callback / hook registration API (callbacks.go)#

db.Callback() returns a *callbacks exposing six per-operation *processor objects:

db.Callback().Create()   → *processor
db.Callback().Query()    → *processor
db.Callback().Update()   → *processor
db.Callback().Delete()   → *processor
db.Callback().Row()      → *processor
db.Callback().Raw()      → *processor

Each *processor exposes a fluent hook-registration API:

db.Callback().Create().
    Before("gorm:create").
    Register("myapp:hook", func(db *gorm.DB) { ... })
MethodDescription
Before(name)Constrain new callback to run before named callback
After(name)Constrain new callback to run after named callback
Match(fc)Conditional callback (predicate on *DB)
Register(name, fn)Add a new named callback function
Remove(name)Remove a callback by name
Replace(name, fn)Replace an existing callback
Get(name)Retrieve a callback function by name
Execute(db)Run the compiled pipeline (called internally by finishers)

Model lifecycle hooks (BeforeCreate, AfterCreate, BeforeUpdate, etc.) are ordinary methods on the model struct — they are detected via schema/ reflection and registered as callbacks during RegisterDefaultCallbacks.


Plugin API (interfaces.go)#

type Plugin interface {
    Name() string
    Initialize(*DB) error
}

Registered via db.Use(plugin). Stored in Config.Plugins map keyed by Name(). Initialize(*DB) is called once; plugins typically register callbacks or store state via db.InstanceSet.


Generics API (generics.go) — Go 1.18+#

G[T any](db *DB, opts ...clause.Expression) Interface[T] — a type-safe fluent wrapper around *DB:

userDB := gorm.G[User](db)
users, err := userDB.Where("age > ?", 18).Find(ctx)      // returns ([]User, error)
user,  err := userDB.Where("id = ?", 1).First(ctx)       // returns (User, error)
err        = userDB.Create(ctx, &User{Name: "Alice"})

Key interfaces returned:

InterfaceRole
Interface[T]Root — Raw, Exec, and embeds CreateInterface[T]
CreateInterface[T]Chainable + finisher for create context
ChainInterface[T]Chainable + finisher for query/update/delete context
ExecInterface[T]Finisher methods: First, Last, Take, Find, FindInBatches, Row, Rows, Scan
JoinBuilderType-safe join condition builder
PreloadBuilderType-safe preload condition builder (includes LimitPerRecord)

The generics layer is entirely additive — it wraps the *DB API and returns typed results and errors instead of *DB. It does not change the underlying execution path.


API style summary#

DimensionApproach
Primary styleFluent method chaining on *DB; returns *DB from all methods
Error handlingAccumulated on db.Error (check after finisher, not after each call)
Copy-on-write safetyEach chain clones the Statement — shared *DB is safe to reuse
Configuration*Config struct + Option interface for pre- and post-init hooks
Per-query overridesdb.Session(&Session{...}) or db.WithContext(ctx)
Type safetyinterface{} / any for legacy API; generics via G[T] for new code
Backward compatibilityAdditive only — no method removals; generics API is a new surface layer
Extensibility entry pointsCallback() (pipeline hooks), Use() (plugins), Dialector interface

Notable API design observations#

  1. Error sink pattern. All finishers return *DB rather than (*DB, error). Callers check result.Error after the call. This enables chaining through errors (db.Where(...).Find(...) can be written in one expression) but departs from idiomatic Go error handling. The generics G[T] API fixes this: all finishers return (T, error).

  2. Dual entry points for the same operation. db.Where("id = ?", 1) (string), db.Where(&User{ID: 1}) (struct), and db.Where(map[string]interface{}{"id": 1}) (map) all work. This polymorphism is handled by clause/ AST construction internally, but makes the API surface unusually permissive.

  3. ToSQL for testability. db.ToSQL(func(tx *DB) *DB { return tx.Find(&users) }) returns the generated SQL string without executing — a clean API for testing query construction.

  4. Callbacks as the public extension mechanism. The hook system (db.Callback().Create().Before(...).Register(...)) is the documented, stable way for plugins and user code to extend behavior. This makes the plugin API composable and avoids inheritance.

  5. clause.Expression as an escape hatch. Users can inject raw clause.Expression objects via db.Clauses(...), giving full access to the SQL AST without abandoning the ORM. This is commonly used for database-specific features (ON CONFLICT, RETURNING, FOR UPDATE).