objection.js
A SQL-friendly ORM for Node.js, built on Knex, that gets out of your way instead of hiding SQL behind a DSL.
Repository Health
Technical Analysis
Objection.js is a relational query builder for Node.js layered on top of Knex, the SQL query builder that already handles Postgres, MySQL, and SQLite dialect differences. Rather than wrapping the database in a fully object-oriented abstraction, it gives you declarative model classes with typed relationships, then lets you drop back to raw SQL or Knex’s query builder whenever the ORM would get in the way.
Its standout feature is graph-shaped operations: eager loading arbitrary-depth relation trees with a compact expression syntax, and inserting or upserting entire object graphs (including nested relations) in a single call with automatic diffing. Schema migrations are deliberately left to Knex’s migration tool rather than generated from model definitions, keeping the ORM’s surface area small and predictable.
What You Get
- Declarative Model classes with relationMappings for belongsToOne, hasMany, hasOne, hasOneThrough, and manyToMany relations
- A RelationExpression syntax for eager-loading arbitrarily deep, filtered relation graphs in one query
- insertGraph/upsertGraph operations that write nested object trees in a single call, with automatic graph diffing on upsert
- Full TypeScript typings (typings/objection) checked as part of the test suite via tsc
- Built-in transaction support that composes cleanly with Knex’s transaction objects
- Optional JSON-schema based model validation via AJV, plus typed errors (ValidationError, NotFoundError, RelationDoesNotExistError) instead of silent failures
Common Use Cases
- Modeling relational domain data (users, orders, nested line items) in a Node.js backend without hand-writing every join
- APIs that need to return deeply nested JSON responses assembled from several related tables in one query
- Bulk or nested writes where a whole object graph (a form submission with child records) must be persisted atomically
- Teams that want ORM ergonomics for the common cases but need to fall back to raw SQL or Knex’s query builder for complex reporting queries
- TypeScript codebases that want compile-time checked model and relation definitions
Under The Hood
Architecture Objection.js is organized as a thin, layered wrapper around Knex: Model (lib/model/Model.js) is the base class user models extend, QueryBuilder (lib/queryBuilder/QueryBuilder.js) extends Knex’s own QueryBuilderBase so every Objection query is still a Knex query underneath, and relation-specific logic (belongsToOne, hasMany, hasOne, hasOneThrough, manyToMany) lives in dedicated subclasses of Relation.js that each implement find/insert/update/delete operations. RelationExpression parses the eager-loading string syntax into an internal tree, and the graph/ subdirectory implements insertGraph and upsertGraph as a separate concern layered on top of the base query builder. If the core Model or QueryBuilder abstractions changed, every relation type and the graph-write machinery would need to follow, since they all depend on the same base classes rather than duplicating query-building logic.
Tech Stack The library itself is plain JavaScript (95% of the codebase) with hand-authored TypeScript typings (typings/objection) covering the remaining surface, and it has no build step of its own — it ships lib/ directly. Its only runtime dependencies are ajv and ajv-formats for JSON-schema validation and db-errors for normalizing database error codes across drivers; Knex is a peer dependency, meaning consumers bring their own Knex + database driver (pg, mysql, sqlite3) versions. Tests run against real Postgres, MySQL, and SQLite instances spun up via docker-compose, docs are built with VuePress, and the project targets Node.js 14 and newer.
Code Quality
The test suite is split into unit and integration suites (tests/unit, tests/integration) covering models, query builders, relations, and utilities, and it runs against three real database engines rather than mocks, which is a strong signal for an ORM where dialect-specific SQL generation is easy to get subtly wrong. Error handling favors typed, catchable errors (NotFoundError, ValidationError, RelationDoesNotExistError, ModifierNotFoundError) over generic throws or silent failures. ESLint and Prettier are enforced as part of npm test, TypeScript typings are checked via a dedicated tsc test step, and GitHub Actions CI runs the full suite across a Node 14–24 matrix on every push and pull request.
API Design
The deliberate design choice is to not reinvent a query DSL: QueryBuilder extends Knex’s builder directly, so raw SQL via raw() and ordinary Knex chaining remain available at any point instead of being walled off behind ORM-only methods. Where it does add its own surface — RelationExpression’s compact eager-loading syntax and insertGraph/upsertGraph’s automatic graph diffing — it solves a problem most query-builder-level ORMs leave to the caller: writing and reading deeply nested object trees in one round trip, with relations declared once via a static relationMappings getter on each model.
Used by 4 apps in this directory
Automatisch
Automation · No Code Platforms
Self-hosted, no-code workflow automation that keeps your data on your own servers—a privacy-first alternative to Zapier with 90+ integrations.
Bigcapital
Invoicing Finance
Self-hostable double-entry accounting platform with invoicing, inventory, multi-currency, and real-time financial reporting for small and medium businesses.
Nginx Proxy Manager
Developer Tools · Networking · Security
Manage Nginx reverse proxies and free Let's Encrypt SSL through a beautiful web interface — no Nginx expertise required.
Wiki.js
Knowledge Management · Collaboration
A modern, self-hosted wiki platform built on Node.js with a rich plugin ecosystem for authentication, search, storage, and rendering that adapts to any team's infrastructure.