# At most one database driver in active use

- **Pattern:** `ab-000219` (`ai-slop-code-drift.data-auth-drift.dual-database-driver`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000219
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000219)

## Why it matters

Two actively-used primary database drivers almost always means two separate databases, and every query that spans them is an application-side join with no transaction guarantee. A user update that writes to Postgres and then fails before writing to MongoDB leaves your data permanently inconsistent — there is no rollback across drivers. ISO 25010 functional-suitability degrades when the same logical entity is split across databases: foreign key relationships disappear, referential integrity becomes manual, and migrations must coordinate across two systems. AI-generated code is especially prone to this because each new session starts from scratch and reaches for whatever driver was convenient.

## Severity rationale

Critical because cross-driver data splits eliminate transactional consistency, making partial writes and permanently inconsistent records routine rather than exceptional.

## Remediation

Identify which driver owns fewer files and migrate its data to the primary database. Document the boundary explicitly if both databases are genuinely necessary.

```bash
# Find all files importing each driver
grep -rl "from 'pg'" src/
grep -rl "from 'mongodb'" src/

# After migrating the smaller side:
npm uninstall mongodb
rm src/db/mongo-client.ts
```

If both databases serve distinct purposes (e.g., Postgres for relational data, Redis for caching), document the boundary in `src/db/README.md` so the next AI session doesn't treat them as equivalent and start mixing queries.

## Detection

- **ID:** `dual-database-driver`
- **Severity:** `critical`
- **What to look for:** Apply the three-condition rule against this exact database driver allowlist: `pg`, `pg-promise`, `postgres`, `mysql`, `mysql2`, `mariadb`, `mongodb`, `@mongodb/driver`, `redis`, `ioredis`, `better-sqlite3`, `sqlite3`, `@libsql/client`, `@neondatabase/serverless`, `@vercel/postgres`, `@planetscale/database`, `oracledb`, `tedious`. EXCLUDE Redis from the comparison if it is the only one of its kind (Redis as a cache alongside a primary database is normal and expected — Redis itself is a single-purpose cache, not a primary database driver). Count all REMAINING drivers (after excluding standalone Redis) that meet all three conditions (at least 1 non-escape-hatch importing file). Count all package names and file counts for each library.
- **Pass criteria:** 0 or 1 primary database drivers from the allowlist (excluding standalone Redis) are actively used. When 1 is found, quote its name and report: "Canonical database driver: [name] ([N] importing files)."
- **Fail criteria:** 2 or more primary database drivers actively used — data is split across systems, hard to keep in sync, every cross-system query is application-side joins.
- **Do NOT pass when:** Two Postgres drivers (e.g., `pg` AND `postgres` AND `@neondatabase/serverless`) are all imported. Multiple drivers for the SAME database type still count as drift — they don't share connection pools.
- **Skip (N/A) when:** 0 database drivers from the allowlist appear in `RUNTIME_DEPS` (no direct database access — all data goes through an ORM, or the project is data-free).
- **Detail on fail:** `"2 active database drivers detected: 'pg' (8 importing files) AND 'mongodb' (6 importing files). Two databases means two sources of truth — every cross-DB query is an application-side join."`
- **Remediation:** Two database drivers means two databases — and the AI almost certainly stitched them together with hand-rolled queries that don't transact across systems. Consolidate:

  ```bash
  # Inventory which files use each driver
  grep -rl "from 'pg'" src/
  grep -rl "from 'mongodb'" src/

  # Migrate the smaller side's data to the primary database
  # If you genuinely need both, document the boundary clearly:
  # src/db/postgres-client.ts (primary)
  # src/db/mongo-archive.ts (read-only legacy data)
  ```

  After migration, `npm uninstall` the loser and delete its connection module.

---

## External references

- iso-25010 functional-suitability

Taxons: dependency-coherence, data-integrity

HTML version: https://auditbuffet.com/patterns/ab-000219
