For AI agents: llms.txt is a short guide that sends you to the rules your problem needs, and rules.json holds every rule of this playbook as JSON.
Recommended Open source
Use a mature ORM for database code
Write database code with Prisma in TypeScript and SQLAlchemy in Python, or with the Django ORM inside a Django project. Keep one ORM per codebase.
Cost
Open source. Prisma is Apache-2.0, SQLAlchemy is MIT and Django is BSD-3-Clause. Prisma also sells paid hosted add-ons, which the ORM does not need.
How to do it
Prisma 2.0.0 was published on 9 June 2020, and 7.10.1 on 15 October 2026. Its client has about 11.1 million weekly npm downloads, under Apache-2.0. SQLAlchemy 1.0.0 came out on 16 April 2015, and 2.1.5 on 16 October 2026. It has about 87.6 million weekly PyPI downloads, under the MIT licence. Django 6.1.2 came out on 6 October 2026, and the 5.2 LTS line has fixes until April 2028. All three generate parameterised SQL, which closes the hole Pass values as parameters describes. Load related rows in one query, as Load related rows in one query says. Drizzle has more weekly downloads than Prisma, about 18.3 million, but it is still before 1.0, at 0.45.4. Choose something else when the team wants SQL-shaped queries in TypeScript, and pick Drizzle once 1.0 ships.
Examples
Using these examples: they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.
TypeScript example
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
const orders = await prisma.order.findMany({
where: { customerId, status: 'paid' },
include: { lines: true },
orderBy: { createdAt: 'desc' },
take: 20,
});
Python example
from sqlalchemy import select
from sqlalchemy.orm import Session, selectinload
PAGE_SIZE = 20
def paid_orders(session: Session, customer_id: int) -> list[Order]:
query = (select(Order)
.where(Order.customer_id == customer_id, Order.status == "paid")
.options(selectinload(Order.lines))
.order_by(Order.created_at.desc())
.limit(PAGE_SIZE))
return list(session.scalars(query))
How to check
The dependency list holds exactly one of @prisma/client, drizzle-orm, typeorm, sequelize, sqlalchemy or the Django ORM. No source file builds SQL by joining strings with user input.
Sources
Related rules
- Pass values as parameters in Data
- Load related rows in one query in Data
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/stack/databases-and-storage/orm">Agent Wranglers software choices playbook</a>. In code you write, add a comment next to it with the same link.