PostgreSQL ORM,
the Go way
package main
import (
"context"
"time"
"github.com/kintsdev/norm"
)
type User struct {
ID int64 `db:"id" norm:"primary_key,auto_increment"`
Email string `db:"email" norm:"unique,not_null,index,varchar(255)"`
Username string `db:"username" norm:"unique,not_null,varchar(50)"`
Password string `db:"password" norm:"not_null,varchar(255)"`
IsActive bool `db:"is_active" norm:"default:true"`
CreatedAt time.Time `db:"created_at" norm:"not_null,default:now()"`
DeletedAt *time.Time `db:"deleted_at" norm:"index"`
Version int64 `db:"version" norm:"version"`
}
func main() {
cfg := &norm.Config{Host: "127.0.0.1", Port: 5432, Database: "postgres"}
kn, _ := norm.New(cfg)
defer kn.Close()
// Auto-migrate schema from struct tags
_ = kn.AutoMigrate(&User{})
// Generic repository — full CRUD out of the box
repo := norm.NewRepository[User](kn)
_ = repo.Create(context.Background(), &User{Email: "[email protected]"})
}
Everything you need
for PostgreSQL in Go
From auto-migrations and fluent queries to transactions, read/write splitting, and circuit breakers — all in one lightweight package.
Auto-Migration
Schema migrations from struct tags. Creates tables, columns, indexes, foreign keys, renames, and type changes — all idempotent and transactional.
Fluent Query Builder
Chain Select/Where/Join/OrderBy/Limit, raw SQL, inserts with RETURNING, upserts, and keyset pagination.
Generic Repository
Type-safe CRUD with NewRepository[T]. Bulk create, partial update, scopes, soft delete, and optimistic locking built in.
Soft Delete & Versioning
Soft delete by default with HardDelete() override. Optimistic locking via version tag prevents stale writes.
Transactions
TxManager with transaction-bound QueryBuilder. Automatic commit/rollback with clean Go error handling.
Resilience & Splitting
Read/write splitting with transparent routing, exponential retry/backoff, and circuit breaker with open/half-open/closed states.
Three steps to
production Postgres
Define Your Models
Use db and norm struct tags to define columns, indexes, foreign keys, and constraints.
Connect & Migrate
Call norm.New(cfg) to connect, then AutoMigrate(&Model{}) to sync your schema.
Query & Build
Use the repository for CRUD, or the query builder for complex queries. Transactions, caching, and resilience are built in.
Fluent queries with
type-safe results
Chain methods to build complex queries without writing raw SQL. Supports joins, conditions DSL, keyset pagination, soft delete filtering, and more.
Select/Where/Join/OrderBy/Limit/Offsetchaining- Condition DSL:
Eq/Ne/Gt/Lt/In/And/Or INSERT ... RETURNINGandON CONFLICT DO UPDATE- Keyset pagination with
After/Beforecursors
// Fluent query builder
var users []User
_ = kn.Query().
Table("users").
Where("is_active = ?", true).
OrderBy("id ASC").
Limit(10).
Find(ctx, &users)
// Repository with soft delete
repo := norm.NewRepository[User](kn)
_ = repo.Create(ctx, &user)
_ = repo.Delete(ctx, &user) // soft delete
_ = repo.HardDelete(ctx, &user) // permanent
// Upsert with ON CONFLICT
_ = kn.Query().
Table("users").
OnConflict("email").
DoUpdate("username", "updated_at").
Insert(ctx, &user)
type Post struct {
ID int64 `db:"id" norm:"primary_key,auto_increment"`
Title string `db:"title" norm:"not_null,varchar(200)"`
Slug string `db:"slug" norm:"not_null,unique:tenant_slug"`
Tenant int64 `db:"tenant_id" norm:"not_null,unique:tenant_slug"`
UserID int64 `db:"user_id" norm:"not_null,fk:users(id),on_delete:cascade"`
Amount float64 `db:"amount" norm:"type:decimal(20,8)"`
}
// Supported norm tokens:
// primary_key, auto_increment, unique, unique:group
// index, index:name, using:gin|btree|hash
// fk:table(col), on_delete:cascade|restrict
// not_null, default:expr, version
// type:decimal(20,8), varchar(50), text
// rename:old_column, collate:name
Schema as code with
powerful struct tags
Define your entire database schema using Go struct tags. Primary keys, composites, indexes, foreign keys with actions, types, defaults, versioning — everything declarative.
- Composite unique and index groups
- Foreign keys with cascade/restrict/set null actions
- Type overrides:
decimal(20,8),citext,timestamptz - Rename diffs, partial indexes, GIN/btree methods
Built for
speed at scale
Benchmarked on Apple M3 — go test -bench=. -benchmem. Near-zero allocation in hot paths.
StructMapper (cached)
0 alloc · 0 B/op
Keyset Pagination
6 allocs · 112 B/op
SELECT query build
10 allocs · 368 B/op
Placeholder conversion
1 alloc · 144 B/op
PostgreSQL done right
in every Go project
From startup MVPs to regulated financial platforms, Norm gives you the data layer you need without the overhead you don't.
High-Traffic Go APIs
Read/write splitting routes queries to replicas automatically — no manual connection management. PGX v5 means you get the fastest PostgreSQL driver available.
Multi-Tenant SaaS
Soft delete keeps tenant data recoverable and auditable. Combined with optimistic locking, concurrent updates from multiple tenants stay safe.
Financial & Regulated Backends
Optimistic locking prevents double-spend scenarios. Circuit breaker and retry protect against transient DB failures in production trading systems.
Rapid Prototyping & MVPs
Auto-migrations with full history let you evolve your schema as fast as your product changes — without writing migration files by hand.
Microservices with Shared Databases
Embed Norm in each service independently. Each service owns its migrations and connection pool — no shared ORM state across services.
Analytics & Reporting Backends
Fluent query builder generates complex WHERE clauses, JOINs, and aggregations with full type safety — without raw SQL strings scattered across your codebase.
PGX v5
Native PostgreSQL Driver
Auto
Schema Migrations
R/W
Read/Write Splitting
Ready to simplify
your data layer?
Production-ready PostgreSQL ORM with auto-migrations, fluent queries, generic repository, and enterprise resilience features. Open source, MIT licensed.
Frequently asked questions
What is Norm?
Norm is a production-ready ORM and query builder for PostgreSQL in Go, built on top of PGX v5. It provides auto-migrations, a fluent query builder, generic repository, and enterprise features like soft delete, optimistic locking, and circuit breaker.
How is Norm different from GORM?
Norm is built specifically for PostgreSQL with PGX v5 as the driver — meaning it gets the full benefit of PGX performance without the abstraction overhead of a generic multi-database ORM. Norm also ships with built-in read/write splitting, retry logic, and a circuit breaker.
Does Norm support database migrations?
Yes. Norm includes auto-migration support that detects schema differences and applies changes automatically, while maintaining a full migration history for rollback and auditing.
Can Norm handle high-availability PostgreSQL setups?
Yes. Norm supports read/write splitting — routing read queries to replicas and writes to the primary — along with configurable retry and a circuit breaker for resilience under failure.
Is Norm compatible with PGX v5?
Yes. Norm is built on top of PGX v5, inheriting its high-performance PostgreSQL driver and full support for PostgreSQL-specific data types, arrays, and JSON fields.