🇫🇷 Pourquoi j’ai créé @mostajs/orm — 13 bases de données, une seule API, zéro génération de code.
By Dr Hamid MADANI — published on dev.to / Medium / Hashnode
@mostajs/orm is a
Hibernate/JPA-inspired ORM for Node.js & TypeScript that supports
13 databases through a single API (PostgreSQL, MySQL,
MariaDB, SQLite, MongoDB, Oracle, MSSQL, CockroachDB, DB2, SAP HANA,
HSQLDB, Spanner, Sybase). No codegen step. No .prisma DSL.
Just plain TypeScript objects.
Test coverage, stated honestly: 8 of the 13 engines are validated end-to-end — PostgreSQL, MySQL, MariaDB, SQLite, MongoDB, SQL Server, Oracle, HSQLDB (including the WASM runtimes
sqljsandpglite). The other 5 — CockroachDB, DB2, SAP HANA, Spanner, Sybase — are implemented but not yet validated end-to-end (hard-to-provision enterprise/cloud engines). No “coming soon” in disguise: the dialects exist; their E2E test status is disclosed.
If you’ve ever wished Prisma had Hibernate’s depth, or that Drizzle
worked with MongoDB, or that TypeORM was actually maintained — this is
for you. And with its WASM dialects (sqljs
/ pglite), the same code runs in the browser and in
AI dev tools (Bolt.new, StackBlitz, CodeSandbox) with no native
binary — so the starters below open and run in one click.
npm i @mostajs/ormI’ve spent 15+ years writing data layers — Java/Hibernate, Spring Data, then years in the Node ecosystem with TypeORM, Sequelize, Prisma, Drizzle, Mongoose. Each one is great at something, and frustrating at something else.
After shipping ~30 production apps, three pain points kept coming back:
prisma generate
after every schema change. Stale types in CI. Editor lag. Lost minutes
that compound into hours.CascadeType, FetchType,
hbm2ddl.auto, lazy loading proxies — these aren’t bloat,
they’re battle-tested patterns. Node ORMs mostly throw them away.So I built one that fixes the three.
The killer feature. You write your schema once. You change one config line to switch backend.
// SQLite for dev
{ dialect: 'sqlite', uri: './app.db' }
// PostgreSQL for staging
{ dialect: 'postgres', uri: 'postgres://...' }
// MongoDB for that one client who insists
{ dialect: 'mongo', uri: 'mongodb://...' }
// Oracle for the enterprise contract
{ dialect: 'oracle', uri: '...' }The four engines above (SQLite, PostgreSQL, MongoDB, Oracle) are all tested end-to-end — see the TL;DR for the full 8-tested / 5-pending breakdown.
The repository API stays identical:
const users = new BaseRepository<User>(UserSchema, dialect);
await users.create({ email: 'a@b.c', name: 'Alice' });
await users.findOne({ email: 'a@b.c' });
await users.findAll(
{ age: { $gte: 18 }, $or: [{ role: 'admin' }, { verified: true }] },
{ sort: { createdAt: -1 }, limit: 20 },
);That $gte/$or syntax works on PostgreSQL,
MySQL, MongoDB, Oracle — all of them. The dialect adapts.
Why this matters for AI dev tools. When Bolt.new or Cursor generates code, it doesn’t have to “know” your DB. One mental model, every backend.
No prisma generate. No .prisma file. No
DSL.
import type { EntitySchema } from '@mostajs/orm';
export const PostSchema: EntitySchema = {
name: 'Post',
collection: 'posts',
fields: {
title: { type: 'string', required: true, trim: true },
slug: { type: 'string', required: true, unique: true, sparse: true },
content: { type: 'text', required: true },
published: { type: 'boolean', default: false },
},
relations: {
author: { target: 'User', type: 'many-to-one', required: true, onDelete: 'cascade' },
comments: { target: 'Comment', type: 'one-to-many', mappedBy: 'post',
cascade: ['persist', 'remove'], orphanRemoval: true },
},
indexes: [{ fields: ['slug'], type: 'unique' }],
timestamps: true,
softDelete: true,
};That’s it. Type-safe immediately. No build step. Edit the schema, save, hot-reload picks it up.
If you’ve ever used Hibernate, this will feel like home:
| JPA / Hibernate | @mostajs/orm |
|---|---|
@OneToMany, @ManyToOne,
@ManyToMany |
relations: { type: 'one-to-many', ... } |
CascadeType.PERSIST/MERGE/REMOVE/ALL |
cascade: ['persist', 'merge', 'remove'] |
FetchType.LAZY / EAGER |
fetch: 'lazy' \| 'eager' |
@OnDelete(CASCADE) |
onDelete: 'cascade' |
orphanRemoval = true |
orphanRemoval: true |
hbm2ddl.auto = validate/update/create/create-drop |
schemaStrategy: 'validate' \| 'update' \| 'create' \| 'create-drop' |
persistence.xml |
ConnectionConfig |
If you’re a Java dev moving to Node, you’ll be productive in 10 minutes.
const recent = await posts.findAll({
published: true,
createdAt: { $gte: new Date(Date.now() - 7 * 86400000) },
$or: [
{ tags: { $in: ['typescript', 'orm'] } },
{ author: { $in: featuredAuthors } },
],
title: { $regex: /next\.?js/i },
});Works on PostgreSQL. Works on SQLite. Works on MongoDB. Works on
Oracle. The dialect translates $gte → >=,
$in → IN (...), $regex →
LIKE / ~ / $regex, etc.
You don’t learn a new query language per DB. You write MongoDB filters, and they run everywhere.
This is the one nobody talks about, and it’s saved me dozens of hours.
@mostajs/orm ships with a CLI validator that lints your
schemas:
npx mostajs-orm-validator --src ./src24 rules out of the box, including:
softDelete: truefindOne lookup without matching
index → suggests adding onecascade where
requiredfetch: 'eager' without
onDelete → orphans populated silently (auto-fixable)repo.findById(entity.relation)
where relation is lazy → wraps with extractRelId()
automaticallyentity.relation === value under eager fetch → always false
bug (auto-fixable)Try getting that out of Prisma. You can’t.
Need to connect to DB2, SAP HANA, Sybase, or HSQLDB from Node? They have no native Node drivers worthy of production.
@mostajs/orm/bridge exposes a JDBC bridge that runs a
Java sidecar process. Same API, no compromise.
import { BridgeManager, saveJarFile } from '@mostajs/orm/bridge';
await saveJarFile('./drivers/db2.jar');
const dialect = await createConnection({
dialect: 'db2',
uri: 'jdbc:db2://host:50000/MYDB',
});For the enterprise/banking/healthcare crowd, this alone is reason enough to switch.
getDialect() is a singleton for the simple case. For
multi-tenant SaaS where each tenant has its own DB:
import { createIsolatedDialect } from '@mostajs/orm';
const tenantA = await createIsolatedDialect({ dialect: 'postgres', uri: tenantA_URI }, ALL_SCHEMAS);
const tenantB = await createIsolatedDialect({ dialect: 'postgres', uri: tenantB_URI }, ALL_SCHEMAS);
// Concurrent, isolated, type-safebetter-sqlite3 is a native addon — it doesn’t compile in
Bolt.new / StackBlitz / CodeSandbox or on the edge. So
@mostajs/orm ships WASM dialects with the
same API:
sqljs — SQLite compiled to
WebAssembly. Zero native binary, boots in the browser, WebContainers and
edge runtimes.pglite — PostgreSQL in WASM, with
native IndexedDB persistence (uri: 'idb://my-db').// same code, no native binary — boots in Bolt.new on the first try
const dialect = await createConnection(
{ dialect: 'sqljs', uri: ':memory:', schemaStrategy: 'update' },
ALL_SCHEMAS,
);This is why the starters below open and run in AI dev tools
instantly — the thing that makes an ORM discoverable
by Bolt, Lovable, v0 and Cursor. Switch one config line
(dialect: 'postgres') for production; the code is
identical.
| @mostajs/orm | Prisma | Drizzle | TypeORM | Mongoose | |
|---|---|---|---|---|---|
| SQL databases | 12 | 6 | 6 | 8 | 0 |
| MongoDB | ✅ | ❌ (preview) | ❌ | ✅ | ✅ |
| Codegen step | ❌ | ✅ | ❌ | ❌ | ❌ |
| Schema in TS | ✅ | ❌ | ✅ | ✅ (decorators) | ✅ |
| MongoDB-like filters | ✅ | ❌ | ❌ | ❌ | ✅ |
| Hibernate semantics | ✅ | partial | ❌ | partial | ❌ |
| JDBC bridge | ✅ | ❌ | ❌ | ❌ | ❌ |
| Built-in linter | ✅ (24 rules) | ❌ | ❌ | ❌ | ❌ |
| Edge runtime | ✅ (WASM) | ⚠️ (Accelerate $) | ✅ | ❌ | ❌ |
| Browser / WebContainer (Bolt, StackBlitz) | ✅ (WASM) | ❌ | ❌ | ❌ | ❌ |
| Active maintenance | ✅ | ✅ | ✅ | ⚠️ | ✅ |
| License | AGPL-3.0 / commercial | Apache 2.0 | Apache 2.0 | MIT | MIT |
npm i @mostajs/ormimport { createConnection, BaseRepository, type EntitySchema } from '@mostajs/orm';
const UserSchema: EntitySchema = {
name: 'User',
collection: 'users',
fields: {
email: { type: 'string', required: true, unique: true },
name: { type: 'string' },
},
relations: {},
indexes: [],
timestamps: true,
};
const dialect = await createConnection(
{ dialect: 'sqlite', uri: './app.db', schemaStrategy: 'update' },
[UserSchema],
);
const users = new BaseRepository<{ id: string; email: string; name?: string }>(UserSchema, dialect);
await users.create({ email: 'a@b.c', name: 'Alice' });That’s a working app. No codegen. No migrations file. The
schemaStrategy: 'update' reconciles the DB schema on boot
(use 'validate' in production).
@mostajs/orm is AGPL-3.0. If your
project is open source under a compatible license, you’re free to use
it.
For closed-source / SaaS / commercial products, a commercial license is available. Contact mostajs.dev — pricing scales with company size, no per-seat fees, no per-query fees.
This dual-license model funds active development, the same way Sentry, MongoDB, BullMQ Pro, and Cal.com do.
Six public starters, each boots with no native
binary via the sqljs (SQLite WASM) dialect.
Tested E2E (June 2026): StackBlitz 6/6 ✅ ·
CodeSandbox 6/6 ✅ · Bolt.new (the server starters run as-is;
the Next ones run in prod — Bolt’s runtime doesn’t run Next dev).
| Starter | What it shows | Open in |
|---|---|---|
| nextjs / express / fastify / hono -mostajs-orm-starter | Blog (Users · Posts · Comments) — relations, soft-delete, seed | StackBlitz · Bolt · CodeSandbox |
| mostajs-saas-starter | SaaS MVP — landing + auth (@mostajs/auth-lite) + CRUD dashboard | StackBlitz · Bolt · CodeSandbox |
| mostajs-survey-starter | Survey + admin dashboard (bar charts) | StackBlitz · Bolt · CodeSandbox |
📚 Runnable samples —
npx @mostajs/orm-samples scaffold <name> drops one
runnable snippet per feature (relations, soft-delete, transactions,
migrations…).
🤖 MCP server — @mostajs/orm-mcp
is listed in the official MCP Registry
(io.github.apolocine/orm-mcp). In Claude / Cursor / Cline,
ask “generate a mostajs/orm schema” and the AI calls the tool:
generate EntitySchema, lint (24 rules), produce SQL
migrations. A public instance is hosted at
https://orm-mcp.amia.fr/mcp (Streamable HTTP).
Add it to your AI tool — hosted (no install), or
local via npx:
// Hosted (clients that speak HTTP)
{ "mcpServers": { "mostajs-orm": { "url": "https://orm-mcp.amia.fr/mcp" } } }
// stdio-only clients → bridge the hosted server
{ "mcpServers": { "mostajs-orm": {
"command": "npx", "args": ["-y", "mcp-remote", "https://orm-mcp.amia.fr/mcp"] } } }
// Local stdio (the AI tool spawns the process)
{ "mcpServers": { "mostajs-orm": {
"command": "npx", "args": ["-y", "@mostajs/orm-mcp"] } } }
In practice — once connected, you just talk to your AI tool. No SDK, no docs to read:
You: Model a blog: a User has many Posts, each Post has many Comments. Soft-delete everywhere.
AI: → calls mostajs_generate_schema
✓ 3 EntitySchemas (User, Post, Comment) with relations + softDelete
AI: → calls mostajs_validate
✓ 24/24 rules pass — no missing inverse relation, no orphan FK
AI: → calls mostajs_create_migration
✓ SQL migration emitted (postgres) — switch one line for the other 12 dialects
Don’t take my word for it — run the whole chain.
Sample 18-mcp-to-running-app
does this end-to-end: the MCP generates the schemas for an e-commerce
model (users/products/orders), @mostajs/orm applies them,
and the app runs on sqljs (SQLite WASM,
zero native binary) — with an HTML proof report next to
the real insert/select output.
npx @mostajs/orm-samples scaffold 18-mcp-to-running-app ~/demo
cd ~/demo && bash scripts/02-report.sh # → report.htmlConnecting the hosted instance from a stdio-only client looks like this — and that’s the whole setup:
$ npx mcp-remote https://orm-mcp.amia.fr/mcp
[mcp-remote] Connecting to remote server: https://orm-mcp.amia.fr/mcp
[mcp-remote] Connected using StreamableHTTPClientTransport
[mcp-remote] Proxy established between local STDIO and remote server@mostajs/orm is the core — the same schema model powers
a few focused, already-published tools. Each gets its
own deep-dive post soon; the one-liners:
@mostajs/orm-copy-data
— cross-dialect data copy/dump: one source (DB / CSV / JSON / SQL) → N
destinations. Backup, migration, seeding. CLI + API, cron-ready.@mostajs/replicator
— replication manager: master/slave CQRS, cross-dialect CDC, read
routing, failover.@mostajs/replica-monitor
— live web dashboard for the replicator (reads the replication tree
directly — no DB connection needed).@mostajs/orm-cli
— universal CLI: mostajs bootstrap migrates a Prisma
project (codemod + deps + schema convert + DDL) to 13 databases with
zero code change.Same EntitySchema, same 13-database reach — these extend the ORM into backup, replication and migration without a second mental model.
If you like this, a ⭐ on GitHub helps a lot — it’s the strongest signal for AI dev tools (Bolt, Cursor, v0, Lovable) to start surfacing the library.
Tags: #typescript #nodejs
#orm #prisma #drizzle
#nextjs #postgresql #mongodb
#database #hibernate #jpa
#wasm #webcontainer #bolt
#mcp #mostajs