ccppccpp home

Profiles

Drizzle ORM 0.45

Drizzle ORM 0.45.4 + Drizzle Kit 0.31.11 code, configuration, migrations and tooling without 1.0 beta APIs or pre-0.45 habits; any dialect, driver, runtime or app shape. Rule IDs DZ-V/T/C/S/Q/R/X/M/A/Z; NEED TO blocks.

Set this profile

ccpp cpo profile set drizzle-orm

Inside Claude Code, prefix the command with ! to run it in the session. Downloading a profile needs a Builder or Team plan; listing them does not.

Policies

114 policies, grouped by what they guard.

Secrets & private data 3

Credentials, keys and personal data stay out of files, logs, commands and the conversation.

  • dz-c02-command-line-credentials

    DZ-C02 · drizzle-kit commands do not carry database passwords (--password, user:password@ URLs)

  • dz-c02-literal-credentials

    DZ-C02 · Database passwords (connection strings, connection option objects) are not written into source or config; placeholders and application passwords pass

  • dz-q11-sensitive-whole-rows

    DZ-Q11 · Whole-row reads of tables holding secrets (password, token, secret…) select explicit fields

Untrusted input 4

Requests, downloads and tool output are validated before they reach SQL, a shell, eval or a deserializer.

  • dz-q01-unparameterized-sql

    DZ-Q01 · Values reach SQL as parameters: no dynamic text in sql.raw() or untagged strings passed to execute()

  • dz-q02-untrusted-identifiers

    DZ-Q02 · Table, column and sort choices from untrusted input go through a closed mapping, not table[input] or sql.identifier(input)

  • dz-q05-untrusted-write-objects

    DZ-Q05 · Untrusted request objects are not passed or spread whole into .values()/.set(): writable fields are allowlisted

  • dz-q14-unbounded-input-limits

    DZ-Q14 · limit/offset taken from untrusted input are bounded and validated

Destructive actions 7

Deletions, overwrites and irreversible commands wait for the user or a scoped target.

  • dz-c06-shared-database-filters

    DZ-C06 · On a shared database (sharedDatabase), push and pull are restricted with tablesFilter/schemaFilter

  • dz-m04-destructive-generated-sql

    DZ-M04 · Generated migration SQL that drops, renames, narrows or adds constraints is reviewed before it is applied

  • dz-m04-push-force

    DZ-M04 · drizzle-kit push --force (auto-approves data-loss statements) needs the user's confirmation

  • dz-m05-history-removal

    DZ-M05 · Deleting or rewriting recorded migrations (drizzle-kit drop, rm/mv/git rm in the migrations folder) needs the user's confirmation

  • dz-q03-unscoped-mutation

    DZ-Q03 · An executed Drizzle update or delete has a where predicate, unless the bulk write is a recorded exception

  • dz-q04-lsp-optional-predicate

    DZ-Q04 · A mutation's where argument is not typed SQL | undefined (language server: variables and helper results)

  • dz-q04-optional-predicate

    DZ-Q04 · A mutation's where predicate cannot collapse to undefined (all-optional and()/or(), undefined) or a tautology

Weakened checks 2

Suppressions, disabled lint or CI steps and relaxed strictness need a reason or the user's approval.

  • dz-a08-suppressed-diagnostics

    DZ-A08 · Drizzle type errors are fixed, not suppressed with @ts-ignore, @ts-expect-error or @ts-nocheck

  • dz-z03-exception-markers

    DZ-Z03 · Exception markers (// dz-<rule>:) name one rule and give a reason; no blanket disabling of the profile

Type safety 1

No escapes from the type checker (any, unchecked casts, non-null assertions) and explicit contracts.

  • dz-a04-type-erasure

    DZ-A04/A08 · Drizzle tables, columns and results are not erased to any (casts, any-typed generic CRUD wrappers)

Error handling 1

Failures are propagated or handled, never swallowed or turned into fake success.

  • dz-a07-fabricated-success

    DZ-A07 · Query failures are not turned into empty results or defaults ([], null, {}, 0, false) that callers cannot tell apart

Performance & resource bounds 4

Timeouts, bounded retries and fan-out, reused clients, closed resources, no N+1 queries.

  • dz-c07-client-per-call

    DZ-C07 · Database clients and pools are created once per lifecycle, not inside query functions

  • dz-q16-queries-in-loops

    DZ-Q16 · Queries that depend on each row of a loop are reviewed for N+1 (join, relational query, inArray batch)

  • dz-q17-filtering-in-js

    DZ-Q17 · Unfiltered reads are not followed only by JavaScript filtering, counting or summing (push it into SQL)

  • dz-q20-index-evidence

    DZ-Q20 · Several new indexes at once are justified by observed query plans (hint)

Architecture & boundaries 4

Declared layers and dependency directions, no import cycles, small modules, explicit dependencies.

  • dz-a01-schema-runtime-imports

    DZ-A01 · Schema modules stay declarative: no client, driver, framework, env or app-entry imports

  • dz-a02-data-access-boundary

    DZ-A02 · Drizzle queries run only in the modules the project declares for data access (parameter dataAccessPaths)

  • dz-a03-repeated-scope-filters

    DZ-A03 · A predicate repeated three times or more in a file (tenant, soft delete, ownership) becomes one small typed helper; primary-key lookups and join conditions are not scope filters

  • dz-a05-unused-helpers

    DZ-A05 · No speculative scaffolding: new private query helpers have a caller in the file

Databases & queries 32

Schemas, queries, transactions and the ORM used as intended.

  • dz-q06-where-accumulation

    DZ-Q06 · Predicates are combined explicitly: a second .where() on the same builder replaces the first

  • dz-q07-module-level-builder

    DZ-Q07 · Mutable query builders are created per call, not kept at module level and modified by functions

  • dz-q08-duplicated-read-chains

    DZ-Q08 · Optional read filters are composed into one query instead of duplicated if/else chains (hint)

  • dz-q09-null-comparison

    DZ-Q09 · Null tests use isNull/isNotNull, not eq/ne(column, null) or = NULL in SQL

  • dz-q10-sql-type-claims

    DZ-Q10 · sql<number> over count/sum/avg on PostgreSQL decodes the value (mapWith, cast, count()) instead of claiming a type

  • dz-q12-unaliased-subquery-field

    DZ-Q12 · SQL fields selected in a subquery or CTE carry an alias (.as) before they are referenced outside it

  • dz-q13-unordered-pagination

    DZ-Q13 · Paginated reads (offset) have an orderBy, so pages are deterministic

  • dz-q15-unchecked-first-row

    DZ-Q15 · The first row of a select or a findFirst result is checked for absence before it is dereferenced

  • dz-q18-check-then-insert

    DZ-Q18 · Insert-or-update is atomic: no existence check followed by insert/update without conflict handling or locking

  • dz-q19-unexecuted-builder

    DZ-Q19 · Drizzle mutations reach execution: a builder statement without await/return never runs; .execute() is awaited

  • dz-r01-relation-mapping

    DZ-R01 · one() relation mappings pair fields of the declaring table with as many references of the target table

  • dz-r02-ambiguous-relations

    DZ-R02 · Several relations between the same two tables are disambiguated with relationName

  • dz-r03-nested-offset

    DZ-R03 · Relational queries keep offset at the root: 0.45 types nested with-configs without offset

  • dz-r04-extras-aggregates

    DZ-R04 · Relational extras hold aliased per-row SQL, not aggregates (count/sum/… need a subquery or a core query)

  • dz-r05-nested-filters

    DZ-R05 · A nested with-where filters children, not parents (hint once per session)

  • dz-s01-duplicate-identities

    DZ-S01 · One declaration per table and per column name: no second table with the same SQL name, no repeated column name

  • dz-s03-keyless-tables

    DZ-S03 · New tables have a primary key (keyless only for intentional append-only, import or log tables)

  • dz-s04-soft-relations

    DZ-S04 · relations() is not a foreign key: a one() over a column without references()/foreignKey() is flagged

  • dz-s05-join-table-keys

    DZ-S05 · A join table of two foreign keys has a composite primary key or unique constraint over the pair

  • dz-s06-set-null-not-null

    DZ-S06 · ON DELETE/UPDATE SET NULL only targets nullable columns

  • dz-s07-application-defaults

    DZ-S07 · $defaultFn/$onUpdate are application-side only: no DDL, ignored by other writers (hint once per session)

  • dz-s08-null-overrides-default

    DZ-S08 · Inserts and updates do not turn an absent value into null (?? null), which overrides defaults and NOT NULL

  • dz-s09-mirrored-row-types

    DZ-S09 · Row types are inferred from the table ($inferSelect/$inferInsert), not mirrored by hand next to it

  • dz-s10-type-hints

    DZ-S10 · .$type<T>() and text enums are compile-time hints, not validation (hint once per session)

  • dz-s11-numeric-precision

    DZ-S11 · bigint/numeric columns are not decoded as JavaScript number without a stated range

  • dz-s13-repeated-conversions

    DZ-S13 · Repeated JSON/Date conversions of query values are centralized (customType, mapWith or one helper)

  • dz-s14-extension-provisioning

    DZ-S14 · Extension-dependent columns and indexes (pgvector, PostGIS, pg_trgm) come with a CREATE EXTENSION migration

  • dz-x01-independent-writes

    DZ-X01 · Several awaited writes in one function run in a transaction when they form one change

  • dz-x02-handle-outside-transaction

    DZ-X02 · Queries inside a transaction callback use its tx handle, not the outer database handle

  • dz-x03-swallowed-transaction-error

    DZ-X03 · A failed write inside a transaction is rethrown or rolled back, never caught into a normal return

  • dz-x04-effects-in-transaction

    DZ-X04 · Irreversible external effects (HTTP, mail, queues, payments) are kept out of transaction callbacks

  • dz-x05-read-modify-write

    DZ-X05 · Counters and balances are updated in SQL, not read into JavaScript, changed and written back

Schema migrations 9

Migrations come from the tool, applied history stays immutable and risky changes are rolled out safely.

  • dz-m01-schema-workflow

    DZ-M01 · Schema changes follow the declared workflow (migrationWorkflow): no push for migrations, no generate for push, nothing for external

  • dz-m02-push-over-migrations

    DZ-M02 · push on a project that records migrations (a journal exists, workflow not declared) needs the user's confirmation

  • dz-m03-schema-without-migration

    DZ-M03 · A turn that changes table/column/index declarations in a migrations project also generates the migration (once per stop)

  • dz-m05-applied-history

    DZ-M05 · Committed migration SQL files are not edited or rewritten (add a forward migration instead)

  • dz-m06-unregistered-migration

    DZ-M06 · A new SQL file in the migrations folder comes from drizzle-kit generate --custom (the journal registers it)

  • dz-m08-check-warnings

    DZ-M08 · drizzle-kit check warnings (entries the migrator would skip, collisions, malformed snapshots) are unresolved findings

  • dz-m09-journal-order

    DZ-M09 · Journal entries keep strictly increasing when timestamps in entry order (merges of parallel branches included)

  • dz-m11-migrations-at-startup

    DZ-M11 · migrate() has one execution owner: not in request handlers or every server/worker start without a lock

  • dz-t09-custom-migrator

    DZ-T09 · Applying migrations uses drizzle-kit migrate or the driver's migrate(), not a hand-written journal reader or ledger

Versions & deprecated APIs 13

Code matches the installed version, without removed, renamed or deprecated APIs.

  • dz-v01-installed-version

    DZ-V01/Z04 · At session start, Claude learns the installed drizzle-orm/drizzle-kit versions and whether this profile's 0.45/0.31 rules apply

  • dz-v02-v1-relations-api

    DZ-V02 · Drizzle 1.0 relational APIs (defineRelations, db._query, r.one/r.many, object where/orderBy) stay out of 0.45 code

  • dz-v03-unavailable-subpaths

    DZ-V03 · drizzle-orm subpath imports exist in the installed package (no 1.0-only drizzle-orm/zod, /valibot, /_relations…)

  • dz-v04-legacy-index-api

    DZ-V04 · PostgreSQL indexes use the 0.31+ API: ordering and nulls on each column, using(method, …columns)

  • dz-v05-deprecated-apis

    DZ-V05/V12 · New code avoids APIs drizzle-orm 0.45 marks deprecated (InferModel, placeholder/param/name, fromList, positional primaryKey…)

  • dz-v05-lsp-deprecated

    DZ-V05 · No new call resolves to a deprecated Drizzle overload (language server: table extra config, keys, conflict targets, aliases)

  • dz-v05-object-extra-config

    DZ-V05 · Table extra configuration returns an array (the object form is deprecated in 0.45)

  • dz-v06-kit-commands

    DZ-V06/V07 · drizzle-kit is called with commands and flags of the installed 0.31 CLI (no generate:pg, no 1.0 beta commands or flags)

  • dz-v08-named-prepare

    DZ-V08 · Named .prepare() is not used where server-side prepared statements are declared unsupported (postgres-js prepare: false, poolers)

  • dz-v09-manual-identifier-quoting

    DZ-V09 · Identifiers and aliases are escaped by Drizzle (sql.identifier, .as), never quoted or escaped by hand

  • dz-v10-mysql2-mode

    DZ-V10 · drizzle() for mysql2 gets a relational mode (default or planetscale) whenever it gets a schema

  • dz-v11-dialect-returning

    DZ-V11 · MySQL and SingleStore inserts/updates/deletes do not use .returning(); $returningId() returns generated keys only

  • dz-v12-legacy-rewrites

    DZ-V12 · Valid older schema syntax is not rewritten without a defect: explicit column names and serial columns stay as written

Configuration 6

Settings read once at a boundary, validated, with units and without unsafe defaults.

  • dz-c01-kit-config

    DZ-C01 · drizzle.config keys and values exist in drizzle-kit 0.31 (dialect set and valid, no legacy driver/connectionString, no unknown keys)

  • dz-c02-unchecked-connection-env

    DZ-C02 · Runtime clients validate required connection settings at initialization instead of asserting process.env.X!

  • dz-c03-schema-exports

    DZ-C03 · Tables, enums and views in the config's schema files are exported, and new table files are inside the schema globs

  • dz-c04-relational-schema

    DZ-C04 · db.query is used only on a drizzle() instance created with the schema (tables and relations)

  • dz-c05-casing-consistency

    DZ-C05 · The runtime drizzle() casing matches drizzle.config casing, so queries and migrations name columns alike

  • dz-c08-driver-capabilities

    DZ-C08 · No interactive transaction on drivers that throw on it (neon-http, xata-http): use batch() or a session driver

Dependencies & toolchain 15

Packages change through the package manager, lockfiles stay consistent and the project's tools are used.

  • dz-t01-hand-written-manifest

    DZ-T01 · A new package.json without dependencies is initialized with the package manager

  • dz-t01-new-manifest

    DZ-T01/T02 · A new package.json comes from the package-manager initializer (or a generator), and gets its dependencies from the package manager

  • dz-t02-manual-dependency-edit

    DZ-T02 · Dependencies change through the package manager (add/remove/update), never by editing package.json by hand

  • dz-t02-package-manager-call

    Records the tool calls that run a package manager (they may rewrite package.json and lockfiles; DZ-T02/T03)

  • dz-t02-version-lookups

    DZ-T02 · Registry version lookups are not a step before installing

  • dz-t02-version-pins

    DZ-T02 · Packages are installed by name: no guessed exact version, no --save-exact without a reason

  • dz-t03-hand-edited-lockfile

    DZ-T03 · Lockfiles are written by the package manager only (no hand edit, no script rewriting them)

  • dz-t03-resolved-version

    DZ-T03 · After an install that touched drizzle packages, the resolved versions are still on this profile's line

  • dz-t03-stale-lockfile

    DZ-T03 · A turn that changes package.json dependencies also updates the lockfile next to it (once per stop)

  • dz-t04-package-manager

    DZ-T04 · Dependencies are installed with the project's package manager (packageManager field, lockfile)

  • dz-t04-second-lockfile

    DZ-T04 · No second lockfile next to another package manager's lockfile

  • dz-t05-kit-binary

    DZ-T05 · drizzle-kit runs from the project (script or local binary), not from a downloaded or global copy

  • dz-t06-dependency-placement

    DZ-T06 · drizzle-orm and the driver are runtime dependencies, drizzle-kit a dev dependency; only the selected driver is installed

  • dz-t10-locked-installs

    DZ-T10 · CI and container builds restore dependencies from the lockfile (npm ci, --frozen-lockfile, --immutable)

  • dz-v01-install-specs

    DZ-V01/V02 · drizzle packages are not installed at a 1.0 beta/RC tag or a version below this profile's line

Generated files 3

Build outputs, generated code and tool-owned files are regenerated, never edited by hand.

  • dz-m10-migration-ledger

    DZ-M10 · The __drizzle_migrations ledger is never written by hand (no synthetic insert, update or delete of applied rows)

  • dz-t07-hand-transcribed-schema

    DZ-T07 · A schema for an existing database is pulled with drizzle-kit, not transcribed by hand from introspection output

  • dz-t08-migration-metadata

    DZ-T08 · Migration journals and snapshots are written by drizzle-kit (or git), never by hand or by a script

Completion evidence 10

A turn ends with its checks run and passing; claims of success need proof after the last edit.

  • dz-git-call

    Records the tool calls that run git (checkouts and merges rewrite migration metadata legitimately; DZ-T08)

  • dz-kit-call

    Records drizzle-kit runs: the call (for migration files it writes, DZ-T08/M06) and the turn's ledger of kit verbs (DZ-M07, M13)

  • dz-kit-ledger

    Records, per turn, the drizzle-kit verbs and migration runs that succeeded (DZ-M07, M13)

  • dz-m07-up-is-not-migrate

    DZ-M07 · drizzle-kit up (snapshot format upgrade) is not reported as applying migrations to a database (once per stop)

  • dz-m12-tool-output-errors

    DZ-M12 · push/migrate output reporting an error or an abort is treated as a failure even when the exit code is 0

  • dz-m13-migration-evidence

    DZ-M13/Z02 · A turn that adds migrations shows them applied somewhere (migrate, push to a scratch database, or a test) before ending (once per stop)

  • dz-turn-baseline

    Records the work tree when a prompt starts: the baseline of the Drizzle end-of-turn checks (DZ-T03, M03, M13, Z01)

  • dz-z01-evidence-ledger

    Records, per session, Claude's edits (file tools and shell writes) and the typecheck, lint and test runs that succeeded after them (DZ-Z01, M13)

  • dz-z01-new-type-errors

    DZ-Z01/A08 · A turn adds no TypeScript errors to the changed files or their importers (language server, once per stop)

  • dz-z01-required-checks

    DZ-Z01 · A turn that changed Drizzle code ends only after the configured checks (default: typecheck) succeeded on the final files (once per stop)