Intermediate · NoSQL, ORMs and data features · topic 28 of 54 · 30 min
ORMs: working with databases from code
Explanation
What an ORM does
Your code works with objects, like { id: 7, name: "Asha" }. The database works with tables and SQL. An ORM (Object-Relational Mapper) sits between them: you call a method such as user.findMany(), and it builds the SQL, runs it and turns the rows back into objects.
Popular ORMs in 2026
| Language | ORM or query builder | Notes |
|---|---|---|
| TypeScript / Node.js | Prisma | Schema file, generated type-safe client, built-in migrations |
| TypeScript / Node.js | Drizzle | Light, SQL-like syntax, schema written in TypeScript |
| TypeScript / Node.js | TypeORM, Sequelize | Older, class or model based; common in existing projects |
| Python | SQLAlchemy, Django ORM | SQLAlchemy for any app; Django ORM comes with Django |
| Java | Hibernate (JPA) | Standard in Spring Boot projects |
| PHP | Eloquent | Comes with Laravel |
| C# / .NET | Entity Framework Core | Standard in ASP.NET Core |
Models
A model describes one table: its name, its columns and their types, and how it links to other tables. In Prisma you write models in a schema file; in Drizzle, SQLAlchemy or Django you write them as code.
model Customer {
id Int @id @default(autoincrement())
name String
city String?
orders Order[]
}
model Order {
id Int @id @default(autoincrement())
amount Int
customer Customer @relation(fields: [customerId], references: [id])
customerId Int
}// Example only: Prisma Client (needs a database)
const puneCustomers = await prisma.customer.findMany({
where: { city: 'Pune' },
orderBy: { name: 'asc' },
take: 20,
});
const order = await prisma.order.create({ data: { amount: 450, customerId: 2 } });
// Drizzle: the same idea, closer to SQL
const rows = await db.select().from(customers).where(eq(customers.city, 'Pune'));Migrations
A migration is a small, numbered file that changes the database schema: create a table, add a column, add an index. Migrations are kept in Git and run in order on every machine, so your laptop, your teammate and the production server all end up with the same tables. Examples: prisma migrate dev, drizzle-kit generate, Alembic for SQLAlchemy, Django makemigrations.
The N+1 query problem
N+1 happens when you load a list with one query, then run one more query for each item in a loop. For 50 orders that is 1 + 50 = 51 trips to the database. Each trip is small, but together they make the page slow.
N+1 (slow) Fixed (fast)
----------- ------------
Q1: SELECT * FROM orders LIMIT 50 Q1: SELECT orders.*, customers.name
Q2: SELECT * FROM customers WHERE id = 2 FROM orders
Q3: SELECT * FROM customers WHERE id = 1 JOIN customers
Q4: SELECT * FROM customers WHERE id = 3 ON customers.id = orders.customer_id
... LIMIT 50
Q51: SELECT * FROM customers WHERE id = 9
51 round trips 1 round trip// N+1: one query per order inside the loop
const orders = await prisma.order.findMany({ take: 50 });
for (const order of orders) {
order.customer = await prisma.customer.findUnique({ where: { id: order.customerId } });
}
// Fixed: ask the ORM to load the relation in the same request
const ordersWithCustomers = await prisma.order.findMany({
take: 50,
include: { customer: true },
});When to write raw SQL
- Big reports with GROUP BY, window functions or complex joins.
- Bulk updates of thousands of rows in one statement.
- A slow query that you have measured and want to tune by hand.
- Database features the ORM does not support yet.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
ORMs: working with databases from code · 1/7
Writing SQL by hand for every screen gets tiring. Today we look at ORMs, which let you use objects instead.
Prefer a video by a teacher? Find free videos on “prisma orm tutorial for beginners” on YouTube ↗
In real life: A slow "My orders" page in a shopping app
A small online saree shop showed 50 orders per page with the customer name and city. Each page took two seconds. Query logging showed 51 queries: one for the orders and one per order for the customer. Changing the ORM call to include the customer turned it into a single JOIN, and the page loaded in under 100 milliseconds. No new server was needed, just one line of code.
Practice (0/2 done)
The app ran one query for orders and then one query per order to get the customer name (N+1). Replace it with ONE query: return the order id, the customer name and the amount for every order, ordered by order id. Tables: customers(id, name, city) and orders(id, customer_id, amount).
Write a tiny query builder buildSelect(table, where) that returns { sql, params }. For buildSelect("users", { city: "Pune", active: 1 }) it returns { sql: "SELECT * FROM users WHERE city = ? AND active = ?", params: ["Pune", 1] }. With an empty where it returns "SELECT * FROM users" and params []. Values must go into params, never into the SQL text. Table and column names cannot be placeholders, so throw an Error if any of them does not match /^[a-z_][a-z0-9_]*$/i.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Pagination: sending data page by pageNoSQL, ORMs and data features · same module
- Handling file uploads safelyNoSQL, ORMs and data features · same module
- Entity Framework Core: databases with C#C# and .NET · Web APIs with ASP.NET Core and EF Core
- Creating the database: schema, migrations and seed dataFull-Stack Development · Building the backend
- JPA and Spring Data repositoriesJava Programming (Core to Spring Boot) · Spring Boot basics
- SQL injection and how to stop itBackend security
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What does an ORM do?
Answer: Maps rows to objects and writes SQL for you
An ORM translates between objects in your code and rows in the database, generating the SQL.
A page loads 30 posts, then runs one query per post to get its author. How many queries is that?
Answer: 31
1 query for the posts plus 30 for the authors: 31. This is the N+1 problem.
What is a migration?
Answer: A versioned file that changes the database schema
Migrations are numbered schema changes kept in Git, so every environment gets the same tables.
Which ORM comes with the Laravel PHP framework?
Answer: Eloquent
Eloquent is Laravel's ORM. Hibernate is Java, SQLAlchemy is Python and Drizzle is TypeScript.
You need raw SQL for a report. How should you include the user's chosen city?
Answer: As a parameter with a placeholder
Parameters keep values separate from SQL code, which prevents SQL injection.
What does an ORM do?Related
Answer: Maps objects in code to rows in database tables
Object-Relational Mapper.
What is a database migration?Related
Answer: A numbered file that changes the schema by one step, applied in order
Migrations are small, ordered schema changes kept in the repository, so every database can be built the same way.
From Creating the database: schema, migrations and seed data
Which is the safe way to change a production database schema?Related
Answer: Reviewed migration scripts with Flyway or Liquibase
Migrations are versioned and reviewed.
What causes SQL injection?Related
Answer: Joining user input directly into SQL text
When user text is glued into the query, it can change the query itself. That is injection.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “NoSQL, ORMs and data features” before its exam: Pagination: sending data page by page, Handling file uploads safely.
- Exam: NoSQL, ORMs and data features · 14 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Authentication and authorization. 54 topics left in the course before the final exam.