Type-safe CRUD for Drizzle ORM in NestJS.

Configure the connection once in AppModule. Every entity gets the full CRUD surface, type-safe, dialect-aware, and ready to extend.

NestJS 10+Drizzle 0.28+PostgreSQLMySQLSQLite
npm weekly downloadsGitHub stars

Find it useful? Give it a star on GitHub. It helps other NestJS developers find it.

Prerequisites
  1. 1
    Configure once in AppModule
    DrizzleCrudModule.forRoot({
      dialect: 'postgresql',
      connectionString: process.env.DATABASE_URL,
      schema,
    });
  2. 2
    A service is an empty subclass
    export class UsersService extends SqlBaseCrudService<User> {}
  3. 3
    Bind it to its table
    DrizzleCrudModule.forFeature([
      { service: UsersService, table: users },
    ]);

That's it. UsersService now has find, create, update, delete, soft delete, restore, bulk ops, filtering, pagination, and full-text search.

What you get

Compatible with

PostgreSQL
MySQL
SQLite
Node.js
Bun
Deno

Latest releases

Keys compared by the databasev3.8.2
Nov 4, 2026

The tenant key check lets the database compare keys, so citext, SQLite NOCASE and MySQL _bin columns get the answer their collation gives. A malformed key and an ISO date string in a write body are a 400 and a stored date instead of a 500, and a massUpdate with one shared sql value is one UPDATE.

Tighter tenant checksv3.8.1
Nov 4, 2026

Each service resolves its own tenant scope, even when another service hands it its options. Text keys compare exactly, so a key that differs from another tenant's only in case is refused, and nested children get the same key check as their parent. massCreate rolls back when its relations fail to load, and massUpdate takes sql values.

Faster cursor pages, fewer round tripsv3.8.0
Nov 3, 2026

Cursor pages seek to the cursor in an index, so page 9,000 of 200,000 rows takes 0.6 ms instead of 24. Single writes are one statement, mass writes drop their savepoints, a per-id SET groups into one UPDATE per value, big nested loads are chunked, and a stored tsvector column serves full-text search. A new page lists the index each query needs.

Batch limits per statement, tenant-safe keysv3.7.2
Nov 3, 2026

The bound parameter limit is checked on the real statement, against each database's own limit: 65,535 on PostgreSQL and MySQL, 32,766 on SQLite, 100 on D1. A belongs-to key must point inside the caller's tenant, SQLite type errors are 400s, full-text search over several columns keeps rows with a NULL column, caseSensitive works on SQLite, and idleTimeout works on MySQL.

Clearer scoped upsert error on MySQLv3.7.1
Nov 2, 2026

A scoped upsert on MySQL is refused with an error that names both dialects that support it: PostgreSQL and SQLite.

SQLite, MySQL connections, full-text optionsv3.7.0
Nov 2, 2026

dialect: "sqlite" runs on SQLite, libSQL and Cloudflare D1. connectionString builds a mysql2 pool on MySQL, with pool size, SSL and idle timeout options on both drivers, and forRootAsync takes useClass and useExisting. fullTextSearch takes filters, relations and select like findAll, plus a language and websearch queries. MySQL row locks now lock.

Relations follow the tenant scopev3.6.0
Nov 2, 2026

Loaded relations, joins, relation filters and counts only see rows of the caller's tenant. Bulk routes validate their bodies against the DTOs, route decorators that wrap the handler run, and deep filters, huge batches, missing values and MySQL duplicates are 400s and 409s instead of 500s.

Sort default, 400s and scoped countsv3.5.2
Nov 2, 2026

A bare sortBy now sorts ascending in findAll, the same as ?sortBy= over HTTP. Soft delete calls on an entity without soft delete, and full-text search on MySQL, are 400s instead of 500s. Relation counts only count rows in the caller's tenant.

Published as @avytrix/nestjs-drizzle-crudv3.5.1
Nov 2, 2026

The package moves to the @avytrix scope with the same code as 3.5.0. Swap the dependency and the imports for @avytrix/nestjs-drizzle-crud; the MCP server runs with npx -p @avytrix/nestjs-drizzle-crud nestjs-drizzle-crud-mcp. The unscoped name is deprecated.

Controller factory, tenancy, events, lockingv3.5.0
Nov 2, 2026

createCrudController wires every CRUD route with the right id pipe, and ApiCrudList documents list queries in Swagger. A scope keeps every read and write inside one tenant, global events cover bulk writes, a version column turns stale writes into 409s, and filters reach through relation paths with some, none and every. Writes return their relations, lists can count relations or skip COUNT(*).

Query parsing, allowlists, cursors, upsertv3.4.0
Nov 2, 2026

parseQuery turns a query string into typed filters, allowlists keep clients to the columns you choose, and findByCursor pages without OFFSET. Filters gain or / not groups and new operators, sortBy takes several columns or a relation column, soft-deleted rows can be listed and purged, and bulk writes are one statement for the whole set.

Audit fixes: filters, soft delete, bulk errorsv3.3.1
Nov 2, 2026

String and date filters work on every column type, a soft-deleted parent no longer comes back through a join, and bulk calls report only the items that failed in the 400 body. Unknown filter keys, an empty findOne and bad input on reads are now 400s, and every list ends with a primary key sort.

Has-many eager loading without N+1v3.3.0
Aug 10, 2026

Declare a hasMany relation and findAll loads the whole page's children in one extra query, never one per row. options.select now takes dotted paths like region.code, and the package ships an MCP server so any AI agent can read its docs.

Foreign-key mapping restoredv3.2.2
Aug 9, 2026

ForeignKeyViolationException and EntityInUseException are exported again. A create or update pointing at a missing parent row returns 400, and a delete blocked by dependent rows returns 409, instead of a raw 500.

Docs site and packagingv3.2.1
Jul 17, 2026

The package homepage now points at this docs site, and the READMEs link the docs, npm, and GitHub. No runtime change, and the foreign-key regression it carried is fixed in 3.2.2.

Free under MIT, kept that way by sponsors

Dialect quirks, error mapping, and query correctness are ongoing work, given away for free. If this package saves you time, sponsoring is what keeps it maintained.

Sponsor on GitHub