[Atomic Glue](atomicglue.co)
BACKEND
Home › Glossary › Backend· 299 ·

ORM

\\oh-ar-em\\n.
Filed underBackendSoftware Engineering
In brief · quick answer

ORM (Object-Relational Mapping) is a technique that lets developers interact with a relational database using object-oriented code instead of writing SQL directly. It maps database tables to classes and rows to objects.

§ 1 Definition

ORM (Object-Relational Mapping) is a programming technique that bridges the relational database world (tables, rows, columns, SQL) with the object-oriented programming world (classes, objects, methods, properties). An ORM library generates SQL from your object-oriented code and maps query results back to objects. Popular ORMs include Prisma (TypeScript/Node.js), SQLAlchemy (Python), Sequelize (Node.js), TypeORM (TypeScript), Eloquent (PHP/Laravel), Entity Framework (.NET), Hibernate (Java), and Django ORM (Python). ORMs provide significant productivity benefits: you write code in your application's language instead of switching to SQL, you get type safety and autocomplete for database operations, migrations are managed in code, and the ORM handles connection pooling and query parameterization (preventing SQL injection). The tradeoff is a leaky abstraction: ORMs generate SQL, and that generated SQL is sometimes inefficient. A query that would be a simple JOIN in SQL becomes an N+1 disaster in the ORM. Understanding the generated SQL is essential for production use.

§ 2 How ORMs Work

An ORM maps database tables to model classes. Each table becomes a class. Each row becomes an instance of that class. Each column becomes a property of the instance. Relationships (foreign keys) become object references or collections. The ORM translates method calls to SQL queries. For example, User.findByEmail('[email protected]') generates SELECT * FROM users WHERE email = '[email protected]' LIMIT 1 and returns a User object with properties matching the row columns. Query builders (a subset of ORMs) let you construct SQL-like queries programmatically without writing raw SQL strings. Full ORMs also include identity maps (caching already-loaded objects), change tracking (detecting which fields have been modified), lazy loading (loading related objects only when accessed), and eager loading (fetching related objects in the same query).

§ 3 The N+1 Problem

The N+1 query problem is the most common ORM performance trap. It happens when your code loads a list of parent records, then accesses a relationship for each one, triggering a separate query per parent. Example: loading 100 users, then accessing user.posts for each user triggers 101 queries (1 for users, 100 for posts). The ORM's lazy-loading defaults cause this. The fix is eager loading: telling the ORM to fetch the related data in a JOIN upfront. In Prisma: include: { posts: true }. In SQLAlchemy: .options(joinedload(User.posts)). N+1 queries are hard to catch in development (they work fine with 5 test records) and devastating in production (100 users * 10 posts = 1,000+ queries per page load). Monitoring query counts in development is essential.

§ 4 ORM vs Raw SQL: When to Use Each

ORMs excel at standard CRUD operations, simple queries, and rapid development. They reduce boilerplate, prevent SQL injection, and provide type safety. Use an ORM for 80% of your application's database interactions. Write raw SQL for the remaining 20%: complex reports with aggregations, recursive CTEs, bulk operations that need optimizing, database-specific features (PostgreSQL's full-text search, JSON operators, window functions), and performance-critical queries where the ORM generates suboptimal SQL. The best approach is 'ORM-first, raw-SQL-when-needed.' Prisma supports raw queries, SQLAlchemy has text(), and Django has raw(). Good ORMs make it easy to drop down to SQL when the abstraction is not serving you.

§ 5 Note

Common misunderstanding: ORMs eliminate the need to understand SQL. They do not. ORMs are abstractions, and all abstractions leak. You must understand what SQL your ORM generates to debug performance issues, optimize queries, and handle complex operations. Another misconception: ORMs are always slower than raw SQL. For standard CRUD operations, the difference is negligible. The ORM overhead (object construction, change tracking) is microseconds per query, invisible compared to network latency and database execution time. The real risk is ORM-generated SQL that is structurally inefficient (N+1 queries, missing indexes, unnecessary joins). Also: ORMs do not prevent all SQL injection. Raw query methods in ORMs can still be vulnerable if you interpolate user input directly.

§ 6 In code

```typescript
// Prisma ORM (TypeScript)
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

// ORM-style query (generates SQL automatically)
const user = await prisma.user.findUnique({
  where: { email: '[email protected]' },
  include: {
    posts: {
      orderBy: { createdAt: 'desc' },
      take: 5,
    },
  },
});

// Raw SQL when ORM is not enough
const topAuthors = await prisma.$queryRaw`
  SELECT u.name, COUNT(p.id) as post_count
  FROM users u
  JOIN posts p ON p.author_id = u.id
  WHERE p.created_at >= NOW() - INTERVAL '30 days'
  GROUP BY u.id, u.name
  ORDER BY post_count DESC
  LIMIT 10
`;
```

§ 7 Common questions

Q. Should I use an ORM for my project?
A. Yes, for almost every project. ORMs significantly accelerate development, provide type safety, prevent SQL injection for parameterized queries, and handle migrations. Drop to raw SQL when the ORM generates inefficient queries.
Q. Which ORM should I choose?
A. TypeScript/Node.js: Prisma (modern, type-safe, excellent schema management). Python: SQLAlchemy (most powerful, mature) or Django ORM (if using Django). PHP: Eloquent (Laravel). .NET: Entity Framework Core.
Q. What is the N+1 problem?
A. Loading a list of N parent records, then accessing a relationship for each one, causing N additional queries. Fix with eager loading (JOIN-based fetching). Always monitor query counts.
Key takeaways
  • ORM maps database tables to classes and rows to objects, reducing boilerplate and preventing SQL injection.
  • ORMs excel at standard CRUD (80% of queries). Use raw SQL for complex reports and performance-critical operations (20%).
  • The N+1 problem is the most common ORM performance trap. Use eager loading to prevent it.
  • ORMs do not eliminate the need to understand SQL. You must read and optimize generated queries.
How Atomic Glue helps

Atomic Glue uses ORMs on every project to accelerate development and maintain code quality. Prisma is our standard for TypeScript/Node.js backends, SQLAlchemy for Python, and Eloquent for PHP/Laravel. We understand the abstractions well enough to optimize generated SQL, prevent N+1 queries, and drop to raw SQL when needed. ORM expertise is part of our standard Web Development services. Get in touch to build efficient, maintainable database layers.

Get in touch
# ORM

ORM (Object-Relational Mapping) is a technique that lets developers interact with a relational database using object-oriented code instead of writing SQL directly. It maps database tables to classes and rows to objects.

Category: Backend (also: Software Engineering)

Author: Atomic Glue Development Team

## Definition

ORM (Object-Relational Mapping) is a programming technique that bridges the relational database world (tables, rows, columns, SQL) with the object-oriented programming world (classes, objects, methods, properties). An ORM library generates SQL from your object-oriented code and maps query results back to objects. Popular ORMs include Prisma (TypeScript/Node.js), SQLAlchemy (Python), Sequelize (Node.js), TypeORM (TypeScript), Eloquent (PHP/Laravel), Entity Framework (.NET), Hibernate (Java), and Django ORM (Python). ORMs provide significant productivity benefits: you write code in your application's language instead of switching to SQL, you get type safety and autocomplete for database operations, migrations are managed in code, and the ORM handles connection pooling and query parameterization (preventing SQL injection). The tradeoff is a leaky abstraction: ORMs generate SQL, and that generated SQL is sometimes inefficient. A query that would be a simple JOIN in SQL becomes an N+1 disaster in the ORM. Understanding the generated SQL is essential for production use.

## How ORMs Work

An ORM maps database tables to model classes. Each table becomes a class. Each row becomes an instance of that class. Each column becomes a property of the instance. Relationships (foreign keys) become object references or collections. The ORM translates method calls to SQL queries. For example, User.findByEmail('[email protected]') generates SELECT * FROM users WHERE email = '[email protected]' LIMIT 1 and returns a User object with properties matching the row columns. Query builders (a subset of ORMs) let you construct SQL-like queries programmatically without writing raw SQL strings. Full ORMs also include identity maps (caching already-loaded objects), change tracking (detecting which fields have been modified), lazy loading (loading related objects only when accessed), and eager loading (fetching related objects in the same query).

## The N+1 Problem

The N+1 query problem is the most common ORM performance trap. It happens when your code loads a list of parent records, then accesses a relationship for each one, triggering a separate query per parent. Example: loading 100 users, then accessing user.posts for each user triggers 101 queries (1 for users, 100 for posts). The ORM's lazy-loading defaults cause this. The fix is eager loading: telling the ORM to fetch the related data in a JOIN upfront. In Prisma: include: { posts: true }. In SQLAlchemy: .options(joinedload(User.posts)). N+1 queries are hard to catch in development (they work fine with 5 test records) and devastating in production (100 users * 10 posts = 1,000+ queries per page load). Monitoring query counts in development is essential.

## ORM vs Raw SQL: When to Use Each

ORMs excel at standard CRUD operations, simple queries, and rapid development. They reduce boilerplate, prevent SQL injection, and provide type safety. Use an ORM for 80% of your application's database interactions. Write raw SQL for the remaining 20%: complex reports with aggregations, recursive CTEs, bulk operations that need optimizing, database-specific features (PostgreSQL's full-text search, JSON operators, window functions), and performance-critical queries where the ORM generates suboptimal SQL. The best approach is 'ORM-first, raw-SQL-when-needed.' Prisma supports raw queries, SQLAlchemy has text(), and Django has raw(). Good ORMs make it easy to drop down to SQL when the abstraction is not serving you.

## Note

Common misunderstanding: ORMs eliminate the need to understand SQL. They do not. ORMs are abstractions, and all abstractions leak. You must understand what SQL your ORM generates to debug performance issues, optimize queries, and handle complex operations. Another misconception: ORMs are always slower than raw SQL. For standard CRUD operations, the difference is negligible. The ORM overhead (object construction, change tracking) is microseconds per query, invisible compared to network latency and database execution time. The real risk is ORM-generated SQL that is structurally inefficient (N+1 queries, missing indexes, unnecessary joins). Also: ORMs do not prevent all SQL injection. Raw query methods in ORMs can still be vulnerable if you interpolate user input directly.

## In code

## Common questions
Q: Should I use an ORM for my project?
A: Yes, for almost every project. ORMs significantly accelerate development, provide type safety, prevent SQL injection for parameterized queries, and handle migrations. Drop to raw SQL when the ORM generates inefficient queries.
Q: Which ORM should I choose?
A: TypeScript/Node.js: Prisma (modern, type-safe, excellent schema management). Python: SQLAlchemy (most powerful, mature) or Django ORM (if using Django). PHP: Eloquent (Laravel). .NET: Entity Framework Core.
Q: What is the N+1 problem?
A: Loading a list of N parent records, then accessing a relationship for each one, causing N additional queries. Fix with eager loading (JOIN-based fetching). Always monitor query counts.

## Key takeaways

## Related entries


Last updated June 2026. Permalink: atomicglue.co/glossary/orm

Schedule a call

30 min · Video call

1
Date
2
Time
3
Details