Jesse A. Green / notebook

GORM Admin & Architecture Guide

Generated June 2026 from go-gorm/gorm at d0ee5e2

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for engineers, architects, and library integrators who need to understand how GORM works internally, how to configure it for production, how to extend it, and how to operate applications that depend on it. It complements the User Guide, which covers day-to-day API usage.

GORM (gorm.io/gorm) is a pure-Go ORM library — there is no server, daemon, CLI, or background process to deploy. "Operating" GORM means configuring it correctly inside your own Go application and tuning the database connection it manages.


1. Executive Summary

Property Value
Module path gorm.io/gorm
Language Go (go 1.18 minimum; slog logger requires 1.21+)
Type Embeddable ORM library
Runtime dependencies github.com/jinzhu/inflection, github.com/jinzhu/now, golang.org/x/text
Database support Via separate driver packages (gorm.io/driver/*): MySQL, PostgreSQL, SQLite, SQL Server, GaussDB, …
License MIT
Source layout Core package + callbacks/, clause/, schema/, migrator/, logger/, utils/, internal/
Analyzed commit d0ee5e2 (2026-05-11)

GORM's design centers on three ideas:

  1. Structs are the schema. Models are plain Go structs; reflection plus gorm tags drive table/column mapping, constraints, indexes, and relationships.
  2. Everything is a callback pipeline. Create, Query, Update, Delete, Row, and Raw operations each run an ordered list of registered callback functions. This is the primary extension point.
  3. SQL is built from composable clauses. Each statement is assembled from clause.Expression objects (SELECT, WHERE, LIMIT, ON CONFLICT, …) that dialectors render to database-specific SQL.

2. Architecture

2.1 Component overview

        Your application code
                 │
        ┌────────▼─────────┐
        │   *gorm.DB       │  chainable + finisher API (gorm.go,
        │  (Session/clone) │  chainable_api.go, finisher_api.go,
        └────────┬─────────┘  generics.go, association.go)
                 │ builds
        ┌────────▼─────────┐
        │   Statement      │  per-operation state: Model, Schema,
        │  (statement.go)  │  Clauses, Vars, ReflectValue, SQL
        └────────┬─────────┘
                 │ executed by
        ┌────────▼─────────┐      ┌──────────────────────┐
        │  callbacks       │◄────►│  schema.Schema cache  │
        │ (processor/      │      │  (schema/*.go)        │
        │  callback)       │      │  fields, relations,   │
        │  callbacks/*.go  │      │  indexes, constraints │
        └────────┬─────────┘      └──────────────────────┘
                 │ builds SQL from
        ┌────────▼─────────┐
        │  clause.*        │  SELECT/WHERE/JOIN/LIMIT/ON CONFLICT/…
        │  (clause/*.go)   │
        └────────┬─────────┘
                 │ rendered + executed by
        ┌────────▼─────────┐      ┌──────────────────────┐
        │  Dialector       │      │  ConnPool             │
        │ (driver package) │─────►│  database/sql pool    │
        │  Explain/QuoteTo/ │      │  or PreparedStmtDB    │
        │  BindVarTo/...   │      │  (prepare_stmt.go)    │
        └──────────────────┘      └──────────────────────┘
                                            │
                                       Your database

2.2 The core types

Type File Role
DB gorm.go The handle users interact with. Wraps *Config, Error, RowsAffected, Statement, and an internal clone counter for chain semantics.
Config gorm.go All global behavior knobs (see Section 4).
Session gorm.go A set of per-scope overrides applied via db.Session(...).
Statement statement.go Mutable per-operation builder: the model, parsed schema, accumulated clauses, bind vars, reflect value, and the strings.Builder for SQL.
Dialector interfaces.go The driver contract — Name, Initialize, Migrator, DataTypeOf, BindVarTo, QuoteTo, Explain.
ConnPool interfaces.go The minimal database/sql-style execution surface (ExecContext, QueryContext, …).
Schema schema/schema.go Parsed, cached representation of a model: fields, relationships, indexes, constraints.

2.3 The clone / chain model

DB methods return a *DB, but they do not mutate the original handle. The clone field (set to 1 at Open) governs this: when clone > 0, getInstance() produces a fresh *DB with a new (or cloned) Statement before applying the call. This is what makes the following safe:

base := db.Where("active = ?", true) // base carries one WHERE
adults := base.Where("age >= ?", 18) // a distinct chain
minors := base.Where("age < ?", 18)  // another distinct chain — base is untouched

Important

A *gorm.DB obtained from a finisher should not be reused as a "clean" handle — it carries the accumulated statement. For a fresh, condition-free handle, start a new session: db.Session(&gorm.Session{NewDB: true}) (or simply use the root db).

2.4 The callback pipeline (the heart of GORM)

Every high-level operation dispatches to one of six processors — create, query, update, delete, row, raw — each holding an ordered list of callbacks. RegisterDefaultCallbacks (in callbacks/callbacks.go) wires the defaults:

Processor Default callback order
Create begin_transaction → before_create → save_before_associations → create → save_after_associations → after_create → commit_or_rollback_transaction
Query query → preload → after_query
Update begin_transaction → setup_reflect_value → before_update → save_before_associations → update → save_after_associations → after_update → commit_or_rollback_transaction
Delete begin_transaction → before_delete → delete_before_associations → delete → after_delete → commit_or_rollback_transaction
Row row
Raw raw

The begin_transaction / commit_or_rollback_transaction pair is only registered when SkipDefaultTransaction is false (via processor.Match(enableTransaction)), which is why every single write is, by default, atomic.

processor.Execute (callbacks.go) is the engine: it runs pending scopes, parses the model into a Schema, sets up the reflect value, runs each callback function in order, then emits a Logger.Trace line with the final SQL, elapsed time, rows affected, and any error.

2.5 Callback ordering algorithm

Callbacks register with optional Before(name) / After(name) constraints (and the special "*" wildcard for "first"/"last"). sortCallbacks (callbacks.go) performs a constraint-driven topological sort. Conflicting constraints (e.g. a cycle) produce errors like conflicting callback %s with before %s, and duplicate names emit warnings. This is how a plugin can insert itself, say, after gorm:create but before gorm:after_create.

2.6 SQL building via clauses

A Statement accumulates named clauses (statement.AddClause). At execution, callbacks call statement.Build("SELECT", "FROM", "WHERE", ...) to emit each clause in order. The clause/ package defines every clause type — Select, From, Where (with AndConditions/OrConditions/NotConditions), Joins, GroupBy, OrderBy, Limit, Locking, OnConflict, Returning, Insert, Values, Update, Set, Expr, NamedExpr, IN, Eq, With (CTEs), etc. Each implements clause.Expression / clause.Interface and writes dialector-quoted SQL plus bind variables.

2.7 Schema parsing and caching

schema.Parse (schema/schema.go) reflects over a model once and caches the resulting *Schema in a sync.Map (Config.cacheStore), keyed by type. The parse resolves:

  • Fields (schema/field.go) — data type, size, defaults, auto-time, serializers, read/write permissions, all from ParseTagSetting.
  • Relationships (schema/relationship.go) — Belongs To, Has One, Has Many, Many To Many, and Polymorphic, with foreign-key/reference resolution.
  • Indexes (schema/index.go) and Constraints (schema/constraint.go) — CheckConstraint, UniqueConstraint.
  • Naming (schema/naming.go) — the NamingStrategy that converts Go names to table/column names.

Note

Schema parsing is the most reflection-heavy step. Because results are cached per type, the cost is paid once per model per process. Several open performance issues (e.g. #7787) propose singleflight to de-duplicate concurrent first-time parses.


3. Requirements

Requirement Detail
Go toolchain 1.18+ for the core and the gorm.G[T] generics API; 1.21+ to use logger.NewSlogLogger
C compiler Only if you choose the SQLite driver (cgo via mattn/go-sqlite3); MySQL/Postgres/SQL Server drivers are pure Go
Database server Whatever your chosen driver targets; SQLite needs only a writable file path
Build tags slog.go is guarded by //go:build go1.21

GORM itself imposes no minimum hardware footprint beyond your application's; its memory use scales with the number of parsed model types and the configured connection pool size.


4. Configuration Reference

Every option lives on gorm.Config (gorm.go) and is passed to gorm.Open. Sessions (gorm.Session) can override a subset per-scope.

4.1 gorm.Config fields

Field Type Default Purpose
SkipDefaultTransaction bool false If true, single Create/Update/Delete are not wrapped in a transaction (faster, less safe).
DefaultTransactionTimeout time.Duration 0 Applies a timeout context to transactions begun via Begin.
DefaultContextTimeout time.Duration 0 Applies a timeout to each operation's context if none is set.
NamingStrategy schema.Namer NamingStrategy{IdentifierMaxLength: 64} Controls table/column/index naming.
FullSaveAssociations bool false If true, association writes upsert the full associated record, not just the FK.
Logger logger.Interface logger.Default (Warn level) SQL/error logger.
NowFunc func() time.Time time.Now().Local() Source of "now" for timestamps — override for UTC or test clocks.
DryRun bool false Build SQL without executing it.
PrepareStmt bool false Cache and reuse prepared statements (LRU + TTL).
PrepareStmtMaxSize int unbounded Max cached prepared statements.
PrepareStmtTTL time.Duration 1h-ish default TTL for cached prepared statements.
DisableAutomaticPing bool false Skip the connectivity Ping() after Open.
DisableForeignKeyConstraintWhenMigrating bool false Don't emit FK constraints during AutoMigrate.
IgnoreRelationshipsWhenMigrating bool false Don't auto-create related tables during migration.
DisableNestedTransaction bool false Don't use save points for nested Transaction calls.
AllowGlobalUpdate bool false Permit updates/deletes with no WHERE clause.
QueryFields bool false SELECT explicit column names instead of *.
CreateBatchSize int 0 Auto-batch Create on large slices.
TranslateError bool false Map driver errors to GORM sentinels (ErrDuplicatedKey, etc.).
PropagateUnscoped bool false Propagate Unscoped into nested statements.
ClauseBuilders map[string]clause.ClauseBuilder empty Override how named clauses are built (advanced).
ConnPool ConnPool from dialector Inject a custom connection pool.
Dialector Dialector from Open arg The database driver.
Plugins map[string]Plugin empty Registered plugins.

Tip

For a production HTTP service, a solid baseline is: PrepareStmt: true, TranslateError: true, a Logger configured to Warn with a SlowThreshold, and NowFunc returning UTC. Keep SkipDefaultTransaction at its default unless profiling shows the per-write transaction is a real bottleneck.

4.2 Naming strategy

schema.NamingStrategy (schema/naming.go) fields:

Field Effect
TablePrefix Prepended to every table name (e.g. "public.").
SingularTable If true, table names are singular (user, not users).
NoLowerCase Disable snake_case lowercasing.
NameReplacer A strings.Replacer-like hook to rewrite identifiers (e.g. "CID" → "Cid").
IdentifierMaxLength Truncate generated identifiers (default 64).
db, _ := gorm.Open(dialector, &gorm.Config{
	NamingStrategy: schema.NamingStrategy{
		TablePrefix:   "app_",
		SingularTable: false,
	},
})

4.3 Logger configuration

logger.Config (logger/logger.go):

Field Purpose
LogLevel One of Silent (1), Error (2), Warn (3), Info (4).
SlowThreshold Queries slower than this are logged at Warn as SLOW SQL. Default 200ms on logger.Default.
Colorful ANSI color output.
IgnoreRecordNotFoundError Suppress logging of ErrRecordNotFound.
ParameterizedQueries If true, the logger redacts bind values (logs ?/$n instead of data) — useful for not leaking PII into logs.
newLogger := logger.New(
	log.New(os.Stdout, "\r\n", log.LstdFlags),
	logger.Config{
		SlowThreshold:             200 * time.Millisecond,
		LogLevel:                  logger.Warn,
		IgnoreRecordNotFoundError: true,
		ParameterizedQueries:      true,
		Colorful:                  false,
	},
)
db, _ := gorm.Open(dialector, &gorm.Config{Logger: newLogger})

On Go 1.21+, logger.NewSlogLogger(slog.Default(), cfg) routes GORM logs through structured log/slog, emitting duration, sql, and rows attributes.

Caution

The logger interpolates bind variables into the SQL string for human readability (logger.ExplainSQL). That string is for display only — never feed it back to the database, and prefer ParameterizedQueries: true in environments where query logs may contain sensitive values.


5. Security

GORM is a library, so its security posture is mostly about how you use it. The relevant facts from the source:

5.1 SQL injection

  • Placeholders are safe. Where, Raw, Exec, etc. parameterize ? and named (@name) arguments through the driver's bind-variable mechanism (Dialector.BindVarTo). User input passed as an argument is never concatenated into SQL.
  • Identifiers and raw fragments are NOT escaped. The first string argument to Where("..."), Order(...), Select(...), Group(...), Table(...), Raw(...), and Joins(...) is treated as SQL. Never build these from untrusted input.

Warning

db.Order(userInput) and db.Where(fmt.Sprintf("name = '%s'", userInput)) are injection vectors. Always pass user data as a bind argument: db.Where("name = ?", userInput). For dynamic column/sort names, validate against an allow-list before interpolating.

5.2 The ExplainSQL warning

logger.ExplainSQL and db.ToSQL produce interpolated SQL strings explicitly documented as unsafe to execute (injection risk). They exist for logging/inspection only.

5.3 Global write protection

GORM blocks Update/Delete without a WHERE clause or primary key (ErrMissingWhereClause), preventing accidental full-table mutation. This guard is bypassed only by an explicit AllowGlobalUpdate session — keep that opt-in tightly scoped.

5.4 Read/write field permissions

Field tags -> (read-only), <- (write-only/creatable), and - (ignored) let you keep sensitive or computed columns out of inserts/updates at the mapping layer, reducing mass-assignment risk.

5.5 Soft deletes and data retention

Models with gorm.DeletedAt are never physically removed by Delete; rows persist with deleted_at set. For data-retention/GDPR-style hard deletes, you must use db.Unscoped().Delete(...).

5.6 Logging parameters

Enable ParameterizedQueries: true to keep bind values (which may be credentials, tokens, or PII) out of SQL logs.


6. Operations

GORM has no process to start, stop, or monitor. "Operations" means managing the database connection it owns and observing query behavior.

6.1 Connection pool management

The pool is the standard library's. Obtain it with db.DB() and tune:

sqlDB, err := db.DB()
sqlDB.SetMaxOpenConns(100)
sqlDB.SetMaxIdleConns(10)
sqlDB.SetConnMaxLifetime(time.Hour)
sqlDB.SetConnMaxIdleTime(30 * time.Minute)
Knob Guidance
SetMaxOpenConns Cap to what your database can handle; too high causes contention server-side.
SetMaxIdleConns Keep ≥ your steady-state concurrency to avoid churn; ≤ MaxOpenConns.
SetConnMaxLifetime Set below the database's/load-balancer's idle timeout to avoid "broken pipe" errors.

6.2 Health checks

sqlDB, _ := db.DB()
if err := sqlDB.PingContext(ctx); err != nil { /* unhealthy */ }

PreparedStmtDB and PreparedStmtTX also implement Ping(), delegating to the underlying *sql.DB.

6.3 Prepared-statement cache

With PrepareStmt: true, GORM wraps the pool in a PreparedStmtDB (prepare_stmt.go) backed by an LRU stmt_store.Store (internal/stmt_store/). Statements are keyed by SQL text, guarded by an sync.RWMutex, and evicted on driver.ErrBadConn or TTL expiry. Call (*PreparedStmtDB).Close() to clear all cached statements (e.g. on reconnect).

Note

Open issue #7788 reports lock contention and a potential goroutine leak in the prepared-statement cache / LRU under high concurrency. If you run PrepareStmt: true at scale, monitor goroutine counts and benchmark against your workload.

6.4 Observability

The logger's Trace is the built-in observability hook: it logs every statement with elapsed time and rows affected, flags slow queries above SlowThreshold, and surfaces errors (other than ignored ErrRecordNotFound). Route it through slog for structured ingestion, or implement logger.Interface to push metrics/traces to your APM.

6.5 Migrations

db.AutoMigrate(&Models...) creates missing tables, adds missing columns and indexes, and updates column types — but never drops columns or tables (non-destructive). For full DDL control use the Migrator() interface:

m := db.Migrator()
m.CreateTable(&User{})
m.HasTable(&User{})
m.AddColumn(&User{}, "Age")
m.CreateIndex(&User{}, "idx_users_name")
m.DropColumn(&User{}, "Obsolete")   // explicit, destructive — your call

The full Migrator interface (migrator.go) covers databases, tables, columns, views, constraints, and indexes; each driver provides a concrete implementation built on the base migrator.Migrator (migrator/migrator.go).

Warning

AutoMigrate is convenient for development and additive production changes, but it will not remove or rename columns and offers no down-migrations or version history. For destructive or auditable schema changes in production, drive DDL through the explicit Migrator methods (or a dedicated migration tool) inside a reviewed change process.


7. Extending GORM

7.1 Plugins

A plugin implements Plugin (Name() string, Initialize(*DB) error) and is registered with db.Use(plugin). Use rejects duplicates by name with ErrRegistered and calls Initialize immediately. Plugins typically register or replace callbacks and/or clause builders.

type MetricsPlugin struct{}
func (MetricsPlugin) Name() string { return "metrics" }
func (p MetricsPlugin) Initialize(db *gorm.DB) error {
	return db.Callback().Query().After("gorm:query").Register("metrics:query", recordQuery)
}

db.Use(MetricsPlugin{})

7.2 Custom callbacks

Insert, replace, or remove behavior anywhere in a processor's pipeline:

db.Callback().Create().Before("gorm:create").Register("audit:stamp", stampActor)
db.Callback().Update().Replace("gorm:update", customUpdate)
db.Callback().Delete().Remove("gorm:before_delete")

7.3 Custom data types (Valuer / Scanner)

Any type implementing driver.Valuer + sql.Scanner works as a column. For SQL-expression-valued types, implement GORM's Valuer interface (GormValue(ctx, *DB) clause.Expr) to inject expressions like ST_GeomFromText(?).

7.4 Serializers

The schema.SerializerInterface (with built-ins JSONSerializer, GobSerializer, UnixSecondSerializer in schema/serializer.go) transforms a Go field to/from its stored representation via the serializer tag (gorm:"serializer:json").

7.5 Writing a dialector

To support a new database, implement the Dialector interface (Name, Initialize, Migrator, DataTypeOf, DefaultValueOf, BindVarTo, QuoteTo, Explain) plus a migrator.Migrator subtype. The existing gorm.io/driver/* packages are the reference implementations.


8. Repository Structure

Path Contents
gorm.go DB, Config, Session, Open, sessions, plugins, ToSQL.
chainable_api.go Chain builders: Model, Where, Select, Joins, Order, Limit, Preload, …
finisher_api.go Executors: Create, First, Find, Save, Update(s), Delete, Count, Transaction, Exec, …
generics.go The type-safe gorm.G[T] API and WithResult.
association.go Association mode (Append/Replace/Delete/Clear/Count).
statement.go The Statement builder and condition parsing.
model.go The gorm.Model convenience struct.
soft_delete.go DeletedAt and the soft-delete query/update/delete clauses.
prepare_stmt.go PreparedStmtDB / PreparedStmtTX caches.
errors.go Exported sentinel errors.
interfaces.go Dialector, Plugin, ConnPool, Tx, Valuer, ErrorTranslator, …
migrator.go Migrator, ColumnType, Index, TableType interfaces; AutoMigrate.
scan.go Row-scanning logic (into structs, maps, primitives, with join nesting).
callbacks/ The default pipeline + Create/Query/Update/Delete/Preload/Row/Raw callbacks.
clause/ Every SQL clause type.
schema/ Model parsing: fields, relationships, indexes, constraints, naming, serializers.
migrator/ Base migrator + ColumnType/Index/TableType concrete types.
logger/ Logger interface, default logger, slog logger, SQL explainer.
utils/ Helpers (FileWithLineNum, string utilities).
internal/lru, internal/stmt_store LRU cache and prepared-statement store.
tests/ Cross-driver integration suite (separate module; uses Docker).

9. Testing Strategy

GORM splits tests into two scopes:

  • In-package unit tests sit beside the code they cover (clause/*_test.go, schema/*_test.go, logger/*_test.go, etc.) and exercise SQL generation, schema parsing, naming, and serialization without a live database.
  • Integration tests live in tests/ as a separate Go module (gorm.io/gorm/tests, go 1.24.0) that depends on the real drivers (gorm.io/driver/mysql, postgres, sqlite, sqlserver, gaussdb). They run against actual databases.

Running the integration suite (from tests/README.md):

cd tests
docker-compose up      # provision MySQL/Postgres/SQL Server/etc.
./tests_all.sh         # run the suite across all dialects

Tip

When contributing or validating a driver, run tests/ against every supported database — behavior (quoting, returning clauses, on-conflict semantics, type mapping) legitimately differs per dialect, and the suite is where those differences are pinned down.

Lint configuration lives in .golangci.yml (golangci-lint v2): enabled linters include cyclop, gocritic, gosec, ineffassign, prealloc, unconvert, unparam, plus gofumpt/goimports formatting.


10. Performance Tuning

Lever Effect
PrepareStmt: true Reuse prepared statements; biggest win for repeated query shapes.
SkipDefaultTransaction: true Removes the implicit per-write transaction; measurable on write-heavy loops.
CreateBatchSize / CreateInBatches Collapse many inserts into batched multi-row statements.
FindInBatches Bound memory for large reads by processing in chunks.
Select / QueryFields Fetch only needed columns; QueryFields avoids SELECT *.
Preload vs Joins Preload issues separate queries (avoids row multiplication); Joins is one query (better for filtering). Choose per access pattern.
Connection pool sizing Match MaxOpenConns/MaxIdleConns to real concurrency (Section 6.1).

The community has filed a coordinated set of performance issues against the analyzed version — useful as a tuning/awareness checklist:

Issue Area
#7786 Hot-path overhead when logger is Silent (Trace closure, time.Now, context).
#7792 Preload efficiency — O(n²) assignment, concurrent loading, batch splitting.
#7791 Reflection and fmt.Sprintf allocations in SQL-building paths.
#7787 singleflight for schema Parse; cache ParseIndexes.
#7789 sync.Pool for Statement and scan buffers to cut per-query allocations.
#7788 Lock contention / goroutine leak in the prepared-statement cache / LRU.
#7790 rows.Close() not deferred in delete/update returning paths — connection leak on panic.

Caution

Issue #7790 (un-deferred rows.Close() on the returning path) and #7788 (prepared-statement cache leak) describe potential connection/goroutine leaks under specific failure modes. If you run at high throughput with Returning clauses or PrepareStmt, monitor open connections and goroutine counts, and confirm against your pinned GORM version whether these are resolved.


11. Known Issues & Behavioral Gotchas

Sourced from errors.go, the code paths, and the project's tracked issues:

  • Zero-value struct conditions/updates are skipped. Passing a struct to Where/Updates ignores zero fields; use maps or Select. (The single most reported source of confusion.)
  • Global writes are blocked. Unconditioned Update/Delete return ErrMissingWhereClause unless AllowGlobalUpdate is set.
  • Error sentinels require TranslateError. ErrDuplicatedKey/ErrForeignKeyViolated/ErrCheckConstraintViolated only surface when TranslateError: true and the driver implements ErrorTranslator; GORM warns at startup if it doesn't.
  • AutoMigrate is additive only. It never drops columns/tables and has no down-migrations.
  • Soft-deleted rows linger. gorm.DeletedAt models need Unscoped().Delete() for true removal.
  • Joins by association requires a defined relationship (issue #7745); otherwise use a raw JOIN ... ON.
  • SavePoint/RollbackTo need driver support (SavePointerDialectorInterface); otherwise ErrUnsupportedDriver. Prepared statements are temporarily detached around save points because some databases (e.g. MySQL 8) don't support them with prepared statements.
  • ColumnType.DecimalSize can panic on partially-populated driver wrappers under concurrent DROP COLUMN (issue #7764) — a driver-interaction edge case.

12. Quick Reference

12.1 Setup

db, err := gorm.Open(driver.Open(dsn), &gorm.Config{
	PrepareStmt:    true,
	TranslateError: true,
	Logger:         logger.Default.LogMode(logger.Warn),
	NowFunc:        func() time.Time { return time.Now().UTC() },
})

12.2 Sentinel errors

ErrRecordNotFound, ErrInvalidTransaction, ErrNotImplemented, ErrMissingWhereClause, ErrUnsupportedRelation, ErrPrimaryKeyRequired, ErrModelValueRequired, ErrModelAccessibleFieldsRequired, ErrSubQueryRequired, ErrInvalidData, ErrUnsupportedDriver, ErrRegistered, ErrInvalidField, ErrEmptySlice, ErrDryRunModeUnsupported, ErrInvalidDB, ErrInvalidValue, ErrInvalidValueOfLength, ErrPreloadNotAllowed, ErrDuplicatedKey, ErrForeignKeyViolated, ErrCheckConstraintViolated.

12.3 Callback management

db.Callback().Create().Before("gorm:create").Register("name", fn)
db.Callback().Query().After("gorm:query").Register("name", fn)
db.Callback().Update().Replace("gorm:update", fn)
db.Callback().Delete().Remove("name")

12.4 Migrator

db.AutoMigrate(&A{}, &B{})
m := db.Migrator()
m.HasTable(&A{}); m.CreateTable(&A{}); m.DropTable(&A{})
m.AddColumn(&A{}, "Field"); m.HasColumn(&A{}, "Field"); m.DropColumn(&A{}, "Field")
m.CreateIndex(&A{}, "idx"); m.HasIndex(&A{}, "idx"); m.DropIndex(&A{}, "idx")
m.CreateConstraint(&A{}, "fk_x"); m.HasConstraint(&A{}, "fk_x")

12.5 Session overrides

db.Session(&gorm.Session{
	NewDB:                  true,  // fresh, condition-free handle
	PrepareStmt:            true,
	SkipDefaultTransaction: true,
	FullSaveAssociations:   true,
	AllowGlobalUpdate:      true,
	DryRun:                 true,
	QueryFields:            true,
	SkipHooks:              true,
	Context:                ctx,
})