Using SQL ORMs with DaloyJS
DaloyJS is database-agnostic. Any SQL client that runs on your target runtime works, so pick the ORM or query layer that fits your team. The framework gives you two primitives that make integration boring (in a good way):
app.decorate("db", client)attaches a shared client to every handler'sstate.app.onClose(async () => client.disconnect())ties cleanup to graceful shutdown.
The recommended pattern
Wrap the database client in a plugin and register it once at the root of your app. Handlers read it from state with full type-safety.
Pick your ORM
- Prisma: schema-first, mature migrations, great DX.
- Drizzle ORM: TypeScript-first, edge-friendly, SQL-like API.
- TypeORM: decorator-based entities for object-oriented teams.
- MikroORM: Data Mapper, Unit of Work, and Identity Map with first-class TypeScript.
- Sequelize: mature Active Record style models with broad SQL dialect support.
Need a platform client instead?
Supabase is not an ORM. It is a hosted Postgres platform with a fetch-based JavaScript client, auth, storage, realtime, and edge-friendly APIs. If that is the shape you need, use Supabase with DaloyJS.
- Supabase: platform client for hosted Postgres + auth via
@supabase/supabase-js.
Keep ORM and ODM separate
This section is intentionally SQL-focused. If you are using MongoDB or Couchbase, jump to the ODM overview and use Mongooseor Ottoman instead of forcing document models into an ORM-shaped abstraction.
Runtime compatibility cheat sheet
| Data layer | Node.js | Bun | Deno | Cloudflare Workers | Vercel |
|---|---|---|---|---|---|
| Prisma | Yes | Yes | Yes | Yes, with Driver Adapters | Yes, with Driver Adapters |
| Drizzle ORM | Yes | Yes | Yes | Yes | Yes |
| TypeORM | Yes | Partial | Partial | No | No |
| MikroORM | Yes | Yes | Partial | No | No |
| Sequelize | Yes | Partial | No | No | No |
| Supabase JS | Yes | Yes | Yes | Yes | Yes |
For edge runtimes (Cloudflare Workers, Vercel), prefer Drizzle or Supabase, or use Prisma with Driver Adapters. TypeORM, MikroORM, and Sequelize all lean on Node-centric runtime assumptions and are best on the Node.js adapter.
Typing the decorated client
Use the exported AppState augmentation point to make decorated clients available on state in every handler:
Transactions
Don't open transactions in middleware. Open them inside the handler that owns the unit of work, so your contract response (success or error) maps cleanly onto commit / rollback.
Errors
Translate database errors into framework errors so they serialize as problem+json automatically: