Database recipes
The database recipes are four pages of copy-paste prompts for Claude Code, Codex, and Cursor: schema migrations, ORM code, SQL optimization, and NoSQL data models. Every recipe assumes two things: the agent reads the real schema through a read-only connection, and a real database engine, not a human reading the SQL, proves each change safe.
This hub is for developers who let an agent write the database half of a feature. You know the failure: the migration passes on an empty local database, then locks a 40-million-row table in production, or the agent invents a column because it guessed the schema from a model file.
Which database recipe fits your task?
Section titled “Which database recipe fits your task?”Pick by the job in front of you, not by the order of the list.
| Your task | Recipe | The gate that proves it |
|---|---|---|
| Rename, split, or backfill a column without downtime | Database migration patterns | Squawk lint, a parity query that returns zero rows, a rollback per phase |
| Prisma or TypeORM models, N+1 queries, transactions | ORM best practices | Integration tests on real Postgres; query count per request |
| A slow query or a missing index | SQL optimization patterns | Postgres EXPLAIN (ANALYZE, BUFFERS) / MySQL EXPLAIN ANALYZE before and after, on realistic data |
| MongoDB, DynamoDB, Neo4j, or vector data models | NoSQL patterns and strategies | Access-pattern tests against the real engine |
For the end-to-end workflow around these recipes (spec, schema review, rollout), read database development with AI agents.
Connect the agent to your schema before any recipe
Section titled “Connect the agent to your schema before any recipe”A recipe run against a guessed schema produces confident, wrong SQL. Give the agent a read-only view of a local or staging database first. DBHub (Bytebase, npm @bytebase/dbhub 1.3.1 on 2026-09-26) covers Postgres, MySQL, SQL Server, MariaDB, Oracle, and SQLite with one server. Connect it with a role that can only read. The missing write grants are what enforce read-only; default_transaction_read_only only catches accidents, because a session can switch it off. The default-privileges line keeps tables created by later migrations visible to the agent:
-- Run once in psql on the local or staging database, as the role that runs migrations.-- \password prompts for the password, so it never lands in shell history.CREATE ROLE agent_ro LOGIN;\password agent_roGRANT CONNECT ON DATABASE app TO agent_ro;GRANT USAGE ON SCHEMA public TO agent_ro;GRANT SELECT ON ALL TABLES IN SCHEMA public TO agent_ro;ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO agent_ro;ALTER ROLE agent_ro SET default_transaction_read_only = on;DBHub 1.3.1 reads its connection string from the DSN environment variable, so the password never lands in shell history or a committed file. Export AGENT_RO_DSN in your shell from your secret manager or an untracked .env file (the value has the form postgres://agent_ro:<password>@localhost:5432/app). Registration differs only in syntax across the three tools:
claude mcp add dbhub -e DSN="$AGENT_RO_DSN" -- npx @bytebase/dbhub@1.3.1 --transport stdiocodex mcp add dbhub --env DSN="$AGENT_RO_DSN" -- npx @bytebase/dbhub@1.3.1 --transport stdioAdd the server to .cursor/mcp.json. The file holds only a reference to the variable, so it is safe to commit:
{ "mcpServers": { "dbhub": { "command": "npx", "args": ["@bytebase/dbhub@1.3.1", "--transport", "stdio"], "env": { "DSN": "${env:AGENT_RO_DSN}" } } }}The Claude Code and Codex commands save the expanded DSN in plain text in ~/.claude.json (local scope by default) or ~/.codex/config.toml, outside the repository; treat those files as secrets. Cursor’s MCP documentation describes ${env:NAME} interpolation in mcp.json; confirm it works on your Cursor version (for example, check that the server connects) before you commit the file.
DBHub also has its own guardrails, including a read-only mode and a row limit (see its README). Treat them as a second layer; the role’s missing write grants are the control that holds.
Engine-specific servers (Supabase, Neon, Postgres MCP Pro, MongoDB) are compared on database MCP servers.
How do you verify database changes without reading every line?
Section titled “How do you verify database changes without reading every line?”Make the database the reviewer. A change is done when it passes the gate in the table above and the agent attaches the output, not when the SQL looks right.
- Migrations: lint every new migration file with Squawk, then apply, roll back, and re-apply on a disposable copy with production-like volume, and run the parity query until it returns zero. Set
lock_timeoutso a statement that waits for a lock fails fast instead of queuing every write behind it. - Data backfills: compare row counts and a checksum of the affected columns before and after.
- Queries: attach Postgres
EXPLAIN (ANALYZE, BUFFERS)or MySQLEXPLAIN ANALYZEoutput before and after, run on realistic data.EXPLAIN ANALYZEexecutes the statement, so for writes wrap it inBEGIN … ROLLBACKon the disposable copy. - ORM code: integration tests against the real engine, for example in a Testcontainers Postgres; see integration testing and test data management.
A human signs off on one thing: any destructive step (a DROP, the contract phase of expand-contract). That approval goes into the pull request’s evidence bundle.
What breaks when agents write database code?
Section titled “What breaks when agents write database code?”- Invented columns or wrong types. The agent read the ORM model, not the database. Recovery: run the grounding prompt and make “cite the live schema” a rule in
CLAUDE.mdorAGENTS.md. - A migration that is green locally and locks production. The local table had 50 rows. Recovery: rerun the gate on a production-sized copy with
lock_timeoutset, and split the change with the migration patterns recipe. - An ORM rename generated as drop-and-add. The model diff hides the data loss. Recovery: review the generated SQL, not the model file, and require the row-count check on every migration.
- An index that helps one query and slows writes. Recovery: the SQL optimization recipe has the agent estimate the write-amplification cost of every new index and reject duplicates of existing ones.
- The agent wrote to a shared database. Recovery: connect only through the read-only role above, and see permissions and sandboxing for the agent-side limits.