Go Library · PostgreSQL · PGX v5

PostgreSQL ORM,
the Go way

Norm is a production-ready, lightweight ORM and query builder for PostgreSQL on top of PGX v5. Auto-migrations from struct tags, fluent queries, generic repository, soft delete, optimistic locking, transactions, and more.

main.go
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]"})
}
Scroll
Features

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

01

Define Your Models

Use db and norm struct tags to define columns, indexes, foreign keys, and constraints.

02

Connect & Migrate

Call norm.New(cfg) to connect, then AutoMigrate(&Model{}) to sync your schema.

03

Query & Build

Use the repository for CRUD, or the query builder for complex queries. Transactions, caching, and resilience are built in.

Query Builder

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/Offset chaining
  • Condition DSL: Eq/Ne/Gt/Lt/In/And/Or
  • INSERT ... RETURNING and ON CONFLICT DO UPDATE
  • Keyset pagination with After/Before cursors
queries.go
// 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)
models.go
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
Struct Tags

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
Performance

Built for
speed at scale

Benchmarked on Apple M3 — go test -bench=. -benchmem. Near-zero allocation in hot paths.

~8ns

StructMapper (cached)

0 alloc · 0 B/op

~127ns

Keyset Pagination

6 allocs · 112 B/op

~229ns

SELECT query build

10 allocs · 368 B/op

~281ns

Placeholder conversion

1 alloc · 144 B/op

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.