Skip to main content
For Go · Open Source · Apache 2.0

The ORM for Go
that gets out of your way.

Generics-based, immutable query builders, six SQL dialects, and production primitives like multi-tenancy, L2 caching, and OpenTelemetry — without code generation or global state.

PostgreSQLMySQLMariaDBSQLiteMSSQLOracle
6SQL dialects
0code generation
100%Go generics
L2built-in cache
OTelnative tracing

Why I built this.

After running production services on GORM, four patterns kept causing incidents:

  • Every db.Find(&result) forced an interface{} cast the compiler couldn't verify.
  • Column names in WHERE clauses were plain strings with no guard against typos or injection in dynamic queries.
  • N+1 queries appeared silently whenever a Preload was forgotten, only surfacing in slow-query logs hours later.
  • Multi-tenant isolation meant copy-pasting WHERE tenant_id = ? everywhere, relying on discipline instead of enforcement.

Quark is the ORM I wished existed: generics end the casts, SQLGuard validates every identifier at the API boundary, eager loading is explicit, and multi-tenancy is first-class — not an afterthought.

Everything you need at the data layer.

Six core pillars that cover the full lifecycle of a production Go service.

How QUARK compares.

QUARK occupies the space between GORM's pragmatism and Ent's rigour — without code generation.

FeatureQUARKGORMsqlxEnt
Go generics API
SQL injection guard (ident.)
Immutable query builderN/A
Zero code generation
6 SQL dialects
Multi-tenancy built in
Batch ops (4)
L2 cache + invalidation
Native OTel middleware
stdlib *sql.DB pool

✓ Full support  ·  — Partial / plugin-required  ·  ✗ Not available

¹ GORM v2 core API uses interface{}; generic wrappers exist but are not the primary API.  ·  ² GORM & ent protect values via parameterized queries; Quark additionally validates identifiers (column/table names). See SQLGuard.  ·  ³ GORM queries mutate shared state when chained; Session({&gorm.Session{NewDB: true}}) mitigates but is opt-in.  ·  ⁴ GORM supports CreateInBatches; batch DELETE & UPDATE require custom loops.

Cell-by-cell justification with code examples →

Grows with your application.

QUARK keeps the everyday path — query, create, update, delete — minimal and zero-surprise. When your service graduates to multi-tenancy, cache warming, or distributed tracing, those capabilities are already built in and ready to attach.

Explore production features
  • quark.For[T](ctx, client) — generics-based entry point
  • Middleware chain: wrap Query, QueryRow, and Exec independently
  • Lifecycle hooks: BeforeCreate, AfterUpdate, AfterDelete, …
  • L2 cache stores with tag-based cache invalidation on writes
  • TenantRouter: RLS, schema, and database-per-tenant strategies
  • OpenTelemetry spans, query observers, and structured events

Try it locally.

Clone the repo and run the blog-api example in under a minute.

git clone https://github.com/jcsvwinston/quark
go run ./examples/blog-api
curl -s -X POST http://localhost:8080/authors \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice","email":"alice@example.com"}' | jq .
curl -s "http://localhost:8080/posts" | jq .

Jump into the docs.

Organized around how teams adopt an ORM — model, query, evolve, scale.