neoorm
v0.7.4
Published
TypeScript-first PostgreSQL and SQLite ORM with schema DSL, codegen, and typed relations
Maintainers
Readme
NeoOrm
PostgreSQL and SQLite dialects ship today — MySQL and others are on the roadmap.
bun add neoorm pg # PostgreSQL
bun add neoorm # SQLite (no extra driver needed)Requires Node.js 20+ (Node.js 22.5+ for SQLite on Node — or Bun, or pass your own db instance; see SQLite).
Why NeoOrm?
No any. No codegen runtime. No lock-in.
Most ORMs force you to learn their query language, fight their type system, or ship a heavy runtime. NeoOrm takes a different approach: you write a plain TypeScript schema, it generates a typed client, and you write real SQL — amplified by types, not abstracted away.
- Schema as code — one source of truth for types and the database
- Generated client — zero-cost abstractions, full autocomplete
- Relations done right — nested reads, writes, and filters without N+1 footguns
- PostgreSQL powered — arrays, JSONB, PostGIS, enums, full-text, extensions — no abstraction layer that gets in the way. SQLite ships too for local dev and single-file deployments; MySQL and more are coming.
- Migrations built-in — diff your schema, get SQL, deploy. Rollback supported.
Quick start
bunx neoorm init # scaffold schema, config, env file
bunx neoorm migrate dev # generate typed client + first migration, apply itimport { db } from "./neoorm/client.js";
// Create with nested relation write
const user = await db.users.create({
data: {
email: "[email protected]",
profile: { create: { name: "Alice" } },
},
});
// Fetch with typed includes, pagination, and filters
const posts = await db.posts.findMany({
where: { published: true, tags: { some: { slug: "typescript" } } },
orderBy: { createdAt: "desc" },
take: 20,
with: { author: true, _count: { comments: true } },
});Features
Documentation
| Topic | |
|-------|-|
| Getting started | Setup, manual config, env vars, tenant schemas |
| Examples | Copy-paste patterns for schema, queries, relations, and more |
| Schema DSL | Tables, columns, foreign keys, many-to-many |
| Queries | CRUD, where clauses, pagination, aggregates, groupBy, distinct |
| Relation writes | Nested connect/create/disconnect/set/delete |
| Transactions | Interactive, batch, nested, isolation levels |
| Migrations | Deploy, dev, status, rollback, reset |
| CLI reference | All commands and flags |
| Documentation site | Run neoorm docs for a local docs browser |
| Configuration | Config file options reference |
| SQLite | SQLite dialect, drivers, type mapping, limitations |
| Plugins | PostGIS, citext, custom plugins |
See Getting started and Examples to begin, or the blog example for a full schema and queries.example.ts for typed queries and mutations.
API surface
| Import | Purpose |
|--------|---------|
| neoorm | defineConfig, createNeoOrmClient, createNeoOrmClientFromPool, client types |
| neoorm/schema | Schema DSL (defineSchema, table, column builders, fk, many, index, unique, primaryKey) |
| neoorm/sql | Tagged SQL templates (sql), SQL fragment builder, fluent query builder |
| neoorm/plugins | Plugin registry, NeoOrmPlugin, ColumnTypePlugin |
| neoorm/plugins/postgis | PostGIS column types (geometry, geography, point) and spatial operators |
Philosophy
NeoOrm was built because existing TypeScript ORMs either sacrificed type safety for flexibility, or sacrificed flexibility for type safety. We think you shouldn't have to choose.
- Schema is the source of truth — not decorators, not reflection, not a proprietary DSL. Your schema file is plain TypeScript.
- Generated code is a compile-time artifact — no runtime dependency on the schema. Swap the schema, regenerate, everything still compiles.
- SQL is not hidden — the client compiles to parameterized SQL that you can inspect. No magic, no surprises.
- PostgreSQL and SQLite first — we ship Postgres and SQLite dialects and lean into each one's strengths. MySQL and other dialects are on the roadmap and will slot into the same architecture.
License
MIT
