Library / SDK
go-rel/rel avatar
go-rel/rel

REL: a Go database layer built around a testable repository and an extendable query builder

:gem: Modern ORM for Golang - Testable, Extendable and Crafted Into a Clean and Elegant API

786 stars62 forksGoMIT

At a glance

What is it?
REL is a Go ORM-like database layer for layered architecture, with a repository pattern that comes with its own test library, nested transactions, eager loading, composite primary keys, soft deletion, pagination, schema migration and a query builder you can extend or step out of for plain SQL. It installs with a single go get and is MIT licensed.
Who is it for?
REL fits a Go team that has chosen a layered architecture and wants the repository boundary to be a real interface with a test double, and that wants to write queries through a builder without being trapped by one. It does not fit a team that wants an Active Record style model layer, and it does not fit a project on a database outside the adapters it ships.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 22 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the layer is actually for

REL describes itself as a modern database access layer for Golang, and the more precise line is that it is a golang orm-ish database layer for layered architecture. The orm-ish is doing real work in that sentence, because the project is explicitly not modelling your domain as structs with magic attached.

The three words in the description are testable, extendable and crafted into a clean and elegant API, and the feature list shows what each of them means in practice. There is a testable repository with a builtin reltest package, so the seam between your code and the database is a repository interface that a test double can stand in for. There is an extendable query builder that lets you write a query using the builder or plain SQL, which is the escape hatch that keeps a builder from becoming a walled garden. And the nested transactions are seamless, which is what you need when a service method opens a transaction and calls another that wants one too.

The rest of the list covers the features an application layer usually ends up writing: eager loading, composite primary key, multi adapter, soft deletion, pagination and schema migration.

Installation is a single command:

bash
go get github.com/go-rel/rel

The project is MIT licensed, the module path is github.com/go-rel/rel, and the site is go-rel.github.io with the guides linked from the README.

The repository as the testable seam

The reltest package is the most distinctive thing in the feature list and the reason to look at this library at all.

In a layered design, your repository interface is the boundary your service layer talks to. If that interface is defined in your code and the implementation lives behind it, a test can substitute a fake and assert on what the service asked for, with no database anywhere near the test. That is the testability claim in the feature list, and it is a claim about the shape of the library rather than about a helper function.

The reltest package is the built-in half of that. The repository and the test library ship together, so the fake is written against the same interface the real implementation satisfies, and a mismatch between them shows up as a compile error rather than as a test that quietly passes. For a team that writes a lot of service layer code and a lot of tests, that difference in confidence is worth more than a nicer query builder.

The repository layout shows how the pieces are split at the file level, and it is a readable map of the API. There is adapter.go and adapter_test.go for the multi adapter support, association.go and association_meta.go for the association handling that eager loading needs, changeset.go for tracking changes to a record, collection.go for the set operations, column.go, cursor.go for pagination, document.go and document_meta.go for the document model, entity iterator and entity repository files, errors.go, filter_query.go, group_query.go, index.go, instrumentation.go, iterator.go, join_query.go, key.go, map.go and mutation.go, plus grouped directories for group, join and the migrator, and a reltest package alongside them.

The naming is worth noticing for a second reason. A document, a changeset and a collection are not the vocabulary of an Active Record model, and they are not the vocabulary of a query builder either. They are closer to the document database idea, and the choice of names tells you the mental model the project is working from.

The query builder and the plain SQL escape hatch

The description says the query builder allows you to write a query using the builder or plain sql, and the project describes it as elegant yet extendable with a mix of syntactic sugar. That combination is what a query builder in a production codebase has to be.

Syntactic sugar is the part most people like. Composing a filter with a few chained calls, then a join, then a pagination, reads better than assembling the equivalent SQL string, and the sugar is what makes the builder pleasant to use day to day.

The escape hatch is the part that matters in production. A builder that cannot express what you need forces you either to abandon it for a specific query, which fragments your data access code across two styles, or to add escape hatches to the builder until it is a SQL parser with a nicer syntax. REL's position is that both are available, and the file layout supports that: filter_query.go, group_query.go and join_query.go for the query construction, and the same operations exposed as plain SQL when the builder does not fit.

The other features in the list sit in the same layer. Eager loading is what keeps an association from turning into a query per row, which is the classic ORM performance trap. Composite primary key is unusual enough to call out, which suggests the document model supports keys that are not a single field. Soft deletion is a filter applied to every query, which is convenient and which also means every query pays for it. cursor.go in the file list points to cursor based pagination. Schema migration lives in the migrator directory, and force_cascade.go suggests the delete behaviour can be made to cascade rather than be blocked by references.

Where REL is the wrong choice

The first limitation is that a repository pattern is a commitment, and a large one. If your team is small and your services are thin, the indirection through a repository interface plus a document model plus a query builder may be more structure than the problem needs, and the alternative of writing a few well-shaped SQL functions in a package is often less code overall.

The second is the database range. The features listed, including multi adapter support and soft deletion, work across a set of databases, and the topic tags name MySQL and PostgreSQL. A project on a database outside that set has to check the adapters before designing around it, and the migrate path is the one to verify first, because a schema migration tool is the piece that is hardest to replace later.

The third is the release rhythm, and it deserves a plain reading. The tags are v0.43.0 from August 2026, v0.42.0 from March 2024 and v0.41.0 from October 2023, and the last push was on 2026-10-01. The project is still being worked on, with a code climate maintainability badge, a codecov badge, a Go report card badge and a gitter chat, but the gap between v0.42.0 and v0.43.0 is over two years, so the version you install may be much older than the code in the repository, and the API may have moved underneath you.

The comparison with the standard library plus sqlc is the honest one. That route gives you generated types and compile-time checked SQL with no runtime layer at all, and it is a better fit for a team that wants the database to be the source of truth. REL is the better fit for a team that wants a repository interface it can fake in tests, and the reltest package is the deciding factor.

Editorial conclusion

REL fits a Go team that has chosen a layered architecture and wants the repository boundary to be a real interface with a test double, and that wants to write queries through a builder without being trapped by one. It does not fit a team that wants an Active Record style model layer, and it does not fit a project on a database outside the adapters it ships. Before adopting it, read the guides linked from the project site, because the README is a feature list rather than a tutorial, and try the reltest package early, since the testability claim is the main reason to choose this over a more conventional ORM.

Frequently asked questions

What is REL and what is it designed for?

It is a Go ORM-like database access layer for layered architectures, described as testable, extendable and crafted into a clean API. Rather than Active Record style magic, it gives you a repository interface that can be faked in tests, nested transactions, eager loading, composite primary keys, soft deletion, pagination and schema migration.

How do I install REL and where is the documentation?

With `go get github.com/go-rel/rel`. The README points to the guides at go-rel.github.io, and it also links three example projects, a todo backend with Gin, one with Chi and one with Iris, which show the same repository layer used under three different frameworks.

What does the reltest package do?

It is the built-in test library for the repository pattern, listed in the features as a testable repository with builtin reltest package. The point is that the repository is a real interface with a shipped test double, so a service layer test asserts on what the repository was asked for without a database being involved.

Can I use plain SQL with REL?

Yes. The description says the extendable query builder allows you to write a query using the builder or plain sql, and the query construction is split across filter, group and join query files. The escape hatch is what keeps a builder from becoming a walled garden, at the cost of your data access code using two styles.

How actively is REL maintained?

The last push to the repository was on 2026-10-01, but the tagged releases are v0.43.0 from August 2026, v0.42.0 from March 2024 and v0.41.0 from October 2023. The project is still worked on, with a maintainability badge, a coverage badge and a Go report card, but the gap between the last two tags is over two years.

Official sources

  1. go-rel/rel on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/go-rel-rel.svg)](https://hysenlabs.com/projects/go-rel-rel)

Was this useful?