better-drizzle
Reference

Support matrix

Dialect support for reads, relation loading, writes, upsertMany, locks, raw SQL, transactions, and package compatibility.

This page is the practical compatibility matrix for better-drizzle@0.2.x.

Package compatibility

Everything ships in one package, so there is a single version line to track.

RequirementVersion
better-drizzle0.2.x
drizzle-orm peer^0.30.0
typescript peer^5
Node>=18

0.30.0 is the tested floor - 0.29.5 fails the workspace typecheck.

Entrypoints

EntrypointContentsESMCJSTypes
better-drizzlebetter(), definePlugin(), errors, typesYesYesYes
better-drizzle/pluginsplugin authoring APIYesYesYes
better-drizzle/eslintESLint plugin (static guardrails)YesYesYes
better-drizzle/rulesruntime guardrails pluginYesYesYes
better-drizzle/soft-deletesoft delete pluginYesYesYes
better-drizzle/timestampstimestamps pluginYesYesYes
better-drizzle/zodZod schema + validation pluginYesYesYes

Upgrading from the scoped @better-drizzle/* packages? See the 0.2 upgrade guide.

Core delegate API

CapabilityPostgreSQLSQLiteMySQL
findMany, findFirst, findOne, findUniqueYesYesYes
count, exists, paginate, cursorYesYesYes
create, update, delete, upsertYesYesYes
createMany, updateMany, deleteManyYesYesYes
updateEach (single CASE statement)YesYesYes
repository(name)YesYesYes
extends(...), $withContext(meta)YesYesYes
$withState(...), $withoutPlugins()YesYesYes
hooks and pluginsYesYesYes

Relation loading

CapabilityPostgreSQLSQLiteMySQL
nested include / select (batched loader)YesYesYes
inferred many-to-many through junction tablesYesYesYes
per-parent take / skip (row_number())YesYesYes
include._count.select (correlated subqueries)YesYesYes
relation writes: connectYesYesYes
relation writes: disconnect, setYesYesYes
relation loading combined with lockRejectedN/ARejected

Relation loading and row locks are mutually exclusive by design - Drizzle's relational path does not expose lock configuration, so the combination fails fast instead of silently dropping the lock.

Query plans

CapabilityPostgreSQLSQLiteMySQL
.explain() on read helpersYesYesYes
analyze, verbose, costs, timing, summaryYesignoredignored
relation stages under deferredRelationsYesYesYes

SQLite uses EXPLAIN QUERY PLAN; MySQL uses the best available EXPLAIN form. Unsupported flags are reported back under ignoredOptions rather than silently dropped.

JSONB filters and mutations

CapabilityPostgreSQLSQLiteMySQL
typed JSONB scalar pathsYesrejectedrejected
JSONB path mutations (jsonb_set)Yesrejectedrejected
JSONB full-document replacementYesYesYes

Typed JSONB filters require jsonb(...).$type<T>() and support scalar dot paths only. For typed path mutations, both dotted paths and the { json: ... } wrapper check declared object paths and values. Untyped columns keep open path names and JSON-encodable values in both forms. Mutations can write object or array values, create absent ancestors, and preserve existing object ancestors and unrelated keys; overlapping paths are rejected. Full-document replacements are not dialect-gated.

Conflict-handling features

CapabilityPostgreSQLSQLiteMySQL
create({ skipDuplicates: true })YesYesdialect-dependent
createMany({ skipDuplicates: true })YesYesdialect-dependent
skipDuplicates: ['column'] explicit targetsYesYesNo
upsertManyYesYesNo

upsertMany is intentionally native-first and currently supported only on PostgreSQL and SQLite.

Result projection support

CapabilityPostgreSQLSQLiteMySQL
select on readsYesYesYes
include on readsYesYesYes
select / include on single-row writesYesYesYes
select on upsertManyYesYesNo support because upsertMany itself is unsupported
relation include on upsertManyNoNoNo

Raw SQL options

CapabilityPostgreSQLSQLiteMySQL
$raw / $executeRawYesYesYes
$rawUnsafe with allowUnsafeYesYesYes
comment supportBest supportlimitedlimited
timeoutMsdriver-dependentdriver-dependentdriver-dependent
raw hooksYesYesYes

Transactions

CapabilityPostgreSQLSQLiteMySQL
transaction()YesYesYes
nested transactions / savepointsYesYesYes
afterCommit / afterRollbackYesYesYes
retry optionsYesYesYes
isolationLevelYesignoreddriver-dependent
readOnlyYesignoreddriver-dependent
transaction commentPostgreSQL-orientedignoreddriver-dependent

Row locks

CapabilityPostgreSQLSQLiteMySQL
lock: 'update' / lock: 'share'YesrejectedYes
lock: 'noKeyUpdate' / lock: 'keyShare'Yesrejectedrejected
skipLocked / noWaitYesN/AYes
tables (lock specific tables)Yesrejectedrejected
locks.transactionsOnlyYesYesYes

Official plugins

PluginPostgreSQLSQLiteMySQL
better-drizzle/rulesYesYesYes
better-drizzle/timestampsYesYesYes
better-drizzle/soft-deleteYesYesYes
better-drizzle/zodYesYesYes

better-drizzle/eslint is dialect-independent - it is a static linter, not a runtime plugin.

Policy

When a feature is not safely supported by the current dialect, better-drizzle prefers to fail fast with a structured error instead of silently degrading to a slower or weaker implementation.

On this page