Open-source project
upper/db avatar
upper/db

upper/db: one Go data access layer behind seven database adapters

Data Access Layer (DAL) for PostgreSQL, CockroachDB, MySQL, SQLite and MongoDB with ORM-like features.

3,657 stars236 forksGoMIT

At a glance

What is it?
A query builder and DAL that keeps the SQL you write portable across PostgreSQL, MySQL, MSSQL, CockroachDB, MongoDB, QL and SQLite, with a released v4 line whose last tagged build is well behind the last commit.
Who is it for?
upper/db earns its place when one Go service genuinely has to talk to two of these engines and you refuse to write the dialect branching yourself. It is a weaker choice if your only target is PostgreSQL, where the ecosystem already has several query builders, and a poor fit for a project that wants a full ORM, since the repository ships a builder and helpers rather than schema migration and identity mapping.
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 3 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 6, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A README that lists seven adapters and describes five

Start with the mismatch, because it is the first thing a reader hits. The repository description says upper/db is a data access layer for PostgreSQL, CockroachDB, MySQL, SQLite and MongoDB with ORM-like features. The README's own list has seven entries: PostgreSQL, MySQL, MSSQL, CockroachDB, MongoDB, QL and SQLite, each linking to its own page on upper.io under the v4 documentation path. MS SQL Server and QL are in the README and absent from the one-line description, which is the kind of gap that matters if you are scanning topics rather than reading the project.

Both lists are consistent with the repository topics, which include cockroachdb, mongodb, mysql, postgresql, sqlite, sql, nosql and orm. So the honest reading is that the description is an abbreviated summary rather than a wrong list, and the README is the authoritative inventory. Practical consequence: if you are filtering tooling by repository metadata you will miss two adapters, and the two you miss are the two with the least obvious support, since neither is a mainstream choice outside its own ecosystem.

The README is short by design. Beyond the adapter list it offers a tour at tour.upper.io with live runnable examples in the browser, points documentation and code samples at upper.io/v4, and restates that the code is licensed under the MIT License with a LICENSE file in the repository root. There is no architecture section, no performance claim and no supported-Go-version statement, which means the details a production decision needs are all in the external docs.

What the tree says about where adapters end and the builder begins

The top-level file list is the most informative thing in this repository, because it shows how thin the shared layer is. At the root sit `clauses.go`, `comparison.go`, `cond.go`, `iterator.go`, `union.go`, `intersection.go`, `function.go` and `sql.go`. Those are the portable pieces: clauses, comparisons, conditions, iterators and set operations. Alongside them are `db.go`, `session.go`, `settings.go`, `connection_url.go`, `adapter.go`, `context.go`, `logger.go`, `errors.go`, `result.go`, `record.go`, `marshal.go`, `collection.go` and `raw.go`, which are the session, configuration and value-mapping layers.

The directory layout draws the line. `adapter/` holds the per-database implementations, `internal/` holds shared internals, and `tests/` is a separate top-level directory with its own build entry point. `tests/` being its own directory rather than a set of `_test.go` files beside the code is the structural fact that matters most for anyone planning a contribution or a CI pipeline.

There is also a `Makefile` at the root, and it is short enough to read in full. It sets a log level variable, exposes a benchmark target that runs Go's test harness with a fixed benchtime against `./internal/...`, and exposes a test target that hands control to the `tests` directory:

make
UPPER_DB_LOG          ?= ERROR

That last indirection is the practical detail. Running a plain `go test ./...` from the root is not the same thing as running the suite the way the project defines it, because the test target deliberately does not run Go's package discovery at the root.

Reading go.mod as evidence about adapter support

The module file is more informative than the README about what the adapters actually depend on. The module path is `github.com/upper/db/v4`, which matches the v4 documentation links, and the toolchain floor is declared in two lines:

toml
module github.com/upper/db/v4
go 1.23.0
toolchain go1.23.2

The dependency list is where the interesting tension sits. The main require block includes `github.com/jackc/pgx/v5 v5.7.2` and also `github.com/lib/pq v1.10.9`, which are two different PostgreSQL drivers, and the indirect block includes `github.com/jackc/pgx/v4 v4.18.3`, a third. `github.com/mattn/go-sqlite3 v1.14.24` covers SQLite, `github.com/denisenkom/go-mssqldb v0.12.3` covers MS SQL, `go.mongodb.org/mongo-driver v1.17.3` covers MongoDB and `modernc.org/ql v1.4.11` covers QL.

Three Postgres drivers in one module is not automatically a mistake, since a driver can be present for one adapter's legacy path while another handles the current one, and pgx v4 as an indirect dependency is usually something another package pulled in rather than a choice made here. But it does mean the module is not as small as a query builder has any business being, and anyone doing dependency auditing should expect to explain each of those three rather than assume one of them can go. The MongoDB driver dependency is the other one worth noting: the v4.10.0 release notes say the MongoDB driver was migrated, which means the module-level view of MongoDB support has changed more recently than the README's flat list suggests.

A v4 line with commits but no release since March 2025

The release history and the push history disagree about how active this is, and both numbers are real. The last three releases are v4.8.0 on 2024-06-23, v4.9.0 on 2024-09-08 and v4.10.0 on 2025-03-09. The last push to the repository was on 2026-10-06, and the repository is not archived.

So code is landing on `master` roughly nineteen months after the most recent tag. For a library, that is an ordinary and slightly uncomfortable arrangement. Users who pin to a tag are on code that predates a year and a half of work on the default branch; users who track the default branch are on code no release has ever claimed.

What the releases actually contain also shows where the maintenance effort has gone. v4.10.0 has two entries, migrating the MongoDB driver and upgrading dependencies. v4.9.0 has one, upgrading to pgx v5, which is the change that explains the three-driver module above. v4.8.0 has two, a CockroachDB fix for DELETE with LIMIT and test suite maintenance. That is a dependency-hygiene and compatibility line, not a feature line, which is a reasonable shape for a DAL whose job is to keep working as databases change underneath it.

The default branch is `master`, not `main`, which matters for anyone scripting against the GitHub API or writing CI config that clones a specific ref. The README's test badge points at a workflow named unit-tests, so the badge and the `tests/` directory are consistent with each other even though the Makefile delegates rather than discovers.

What upper/db is compared with sqlx, GORM, and the standard library

The alternative comparison here is not a single project, because upper/db sits between two categories. Against the standard `database/sql` plus a driver, upper/db adds a query builder, composable clauses, iterators, a collection type for result paging and a session abstraction, and it removes per-dialect SQL from your code. That is a real saving when you support several engines, and overhead you pay for nothing when you support one.

Against GORM, the difference is scope. GORM is an ORM: it owns entity modelling, associations, hooks, migrations and lazy loading. upper/db, by its own description and by the shape of its root files, is a DAL with ORM-like features, which means you keep writing the queries and keep owning the SQL. The README's tour is the honest way to judge that difference, because a builder's ergonomics only become clear when you see a real query built in a real page rather than in a snippet.

Against sqlx specifically, the trade is typed scanning. sqlx keeps struct scanning with compile-time field mapping and stays out of query construction. upper/db gives you a builder and a collection abstraction, and its README makes no claim about compile-time struct mapping. If your team relies on struct scanning for type safety, that gap is the first thing to check.

The multi-adapter promise has a cost that the README does not price. A portable query is by construction a query that avoids dialect-specific syntax, so the portable subset is smaller than the intersection most teams assume when they read seven adapters in a list. Feature-flag coverage, and any behaviour a given engine handles differently, live in the v4 documentation rather than on the repository page.

Where the README stops and the docs take over

Everything you need for a decision lives off the repository page. The adapter list on upper.io/v4 is where each engine's supported surface is described, since seven engines cannot be explained in a README this short. The tour at tour.upper.io is the only place in the project where you can see the API used end to end, which makes it a better evaluation tool than the source tree, because the source tree is a list of filenames and the tour is a list of results.

The repository itself is more useful for the operational questions than the feature ones. `logger.go` plus the `UPPER_DB_LOG` variable in the Makefile tell you how much noise you will get in CI output. `errors.go` and `result.go` tell you the project has a deliberate error and result story rather than returning bare driver errors. `settings.go` and `connection_url.go` tell you connection configuration is a first-class part of the API.

On licensing, the MIT grant in the README matches the LICENSE file in the tree, which is the ordinary permissive case with no copyleft obligation and no restrictions on commercial use. The part worth checking before committing is the dependency surface, not the license: three PostgreSQL drivers, a MongoDB driver and an MS SQL driver all enter your build through a single module, and each carries its own maintenance history and its own set of advisories.

One last practical note. The repository is not archived and the last push was 2026-10-06, so the code is moving. What is not moving is the tag series. If you adopt upper/db, decide deliberately whether your dependency pins a tag or tracks the default branch, because the difference between those two choices is nineteen months of untagged commits in one direction and a year and a half of missing fixes in the other.

Editorial conclusion

upper/db earns its place when one Go service genuinely has to talk to two of these engines and you refuse to write the dialect branching yourself. It is a weaker choice if your only target is PostgreSQL, where the ecosystem already has several query builders, and a poor fit for a project that wants a full ORM, since the repository ships a builder and helpers rather than schema migration and identity mapping. Check three things before adopting it: which adapters your target engine needs, since MS SQL and QL are only in the README list, and how far behind your pinned version the last release sits, since v4.10.0 was published on 2025-03-09 while commits continued to 2026-10-06. Run the suite the way the maintainers do, with make test from the repository root, which delegates to the tests directory rather than running everything in one pass.

Frequently asked questions

Which databases does upper/db support?

The README lists seven adapters: PostgreSQL, MySQL, MSSQL, CockroachDB, MongoDB, QL and SQLite. The repository's short description names only five of those, omitting MS SQL and QL, so the README list is the one to trust.

Is upper/db an ORM or a query builder?

It describes itself as a data access layer with ORM-like features. The repository is built around clauses, comparisons, conditions, iterators and set operations at the root, which is query-building machinery rather than an entity mapper with hooks and migrations.

What Go version does upper/db need?

The module file declares `go 1.23.0` with `toolchain go1.23.2`. The README itself does not state a Go version, so the module file is the authoritative statement.

How do I run the upper/db test suite?

The Makefile's test target does not run Go's root package discovery, it delegates to the separate tests directory with `make -C tests`. Benchmarks live in the shared internals and run against ./internal/ with the bench flag.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. upper/db on GitHub
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/upper-db.svg)](https://hysenlabs.com/projects/upper-db)