ORMs

A library that lets application code work with database rows as regular objects, generating SQL behind the scenes instead of you writing it by hand.

What is it?

Writing raw SQL strings inside application code works, but it can get repetitive and error-prone — building queries by concatenating strings, manually mapping columns back into your programming language's objects, and re-typing similar SELECT/INSERT/UPDATE patterns over and over.

An ORM (Object-Relational Mapper) is a library that bridges that gap. It lets you work with rows as regular objects in your programming language — creating a User object, setting its properties, calling .save() — and it translates those actions into the actual SQL statements behind the scenes. You describe what you want in the language you're already writing in, and the ORM generates the how in SQL.

Explain like I'm 10

An ORM is like a translator at a business meeting between two people who speak different languages. You speak your own language (your application code) and the translator (the ORM) converts your requests into the other language (SQL) that the database actually understands, then translates the reply back.

Examples

Raw SQL vs. an ORM (JavaScript, using a Prisma-style ORM)

// Raw SQL
const result = await db.query(
  "SELECT * FROM users WHERE id = $1",
  [userId]
);
const user = result.rows[0];

// With an ORM
const user = await prisma.user.findUnique({
  where: { id: userId },
});

Both approaches fetch the same row, but the ORM version reads like ordinary application code and returns a ready-to-use object, with the SQL generated automatically underneath.

Creating and updating a row through an ORM

const user = await prisma.user.create({
  data: { name: "Amara", email: "amara@example.com" },
});

await prisma.user.update({
  where: { id: user.id },
  data: { email: "amara@newmail.com" },
});

Equivalent to an INSERT followed by an UPDATE statement, but expressed as method calls on objects rather than hand-written SQL strings.

How it works

An ORM keeps a mapping between your programming language's classes or object shapes and the database's tables and columns. When you call a method like .create() or .findUnique(), the ORM builds the corresponding SQL statement, sends it to the database, and converts the raw rows that come back into objects matching your application's data shapes.

Most ORMs also handle a related concern called migrations (versioned scripts that change the schema over time), connection management, and often let you "drop down" to raw SQL for the rare query that's awkward to express through the ORM's own API.

Why does it exist?

Hand-writing SQL for every operation in a large application means a lot of repetitive string-building, manual type conversion, and a bigger surface for mistakes (like accidentally leaving a query open to SQL injection). ORMs exist to remove that repetition, let you stay in one programming language most of the time, and provide safer defaults (like automatically parameterizing values) out of the box.

When to use it

ORMs are a good fit for the majority of everyday application code — straightforward CRUD operations, standard relationships, typical filtering — where the productivity and safety benefits outweigh the abstraction cost.

When not to use it

For complex, performance-critical queries — heavy aggregations, deeply nested joins, database-specific features — an ORM's generated SQL can be inefficient or awkward to express, and writing raw SQL directly (which most ORMs still allow as an escape hatch) is often clearer and faster.

Common mistakes

  • Assuming an ORM automatically produces efficient SQL — it can generate slow queries (like fetching related rows one at a time in a loop) just as easily as hand-written code can.

  • Never learning the underlying SQL, which makes debugging a slow or wrong query much harder when the ORM is the only thing understood.

  • Fighting the ORM to force an awkward query through it, instead of just dropping down to raw SQL for that one case.

Practice exercises

  1. Easy:

    Explain, in your own words, what an ORM does between your application code and the database.

  2. Medium:

    Write the raw SQL equivalent of an ORM call that finds all orders where total_cents is greater than 1000.

  3. Hard:

    Describe a scenario where writing raw SQL directly would be a better choice than using an ORM's query builder.

Interview questions

What is an ORM?

A library that lets you work with database rows as objects in your programming language, translating those object operations into SQL behind the scenes.

What's a downside of relying entirely on an ORM?

It can generate inefficient SQL for complex queries, and developers who never learn the underlying SQL can struggle to debug or optimize slow queries.

Do ORMs prevent you from writing raw SQL when needed?

No — most ORMs provide an escape hatch to run raw SQL directly for cases their query API doesn't handle well.