ORMs and migrations
An application rarely hand-writes SQL strings everywhere, and its schema never stops changing. Two tools manage that relationship over a project's life: an ORM for talking to the database, and migrations for evolving it.
ORMs: objects instead of SQL strings
An object-relational mapper maps tables to classes and rows to objects, so you write user.orders instead of a JOIN. Every ecosystem has one: Prisma and Drizzle (TypeScript), SQLAlchemy and the Django ORM (Python), ActiveRecord (Rails), Hibernate/JPA (Java), Entity Framework (.NET).
What they buy you:
- Speed on ordinary CRUD - create, read, update, delete without writing SQL.
- Safety - they parameterize queries by default, closing the door on SQL injection.
- Portability - much of the code is independent of which database you run.
Where they hurt, and you should drop to raw SQL:
- Complex reports and analytics - heavy aggregations, window functions, and CTEs are often clearer and faster written directly.
- Performance-critical paths - when you need to control exactly what runs.
- The N+1 trap - ORMs make it easy to lazily load related data in a loop, firing one query per row (the N+1 problem). Use the ORM's eager-loading /
JOINoption.
In 2026, typed query builders (Drizzle, Kysely) sit in the middle - close to SQL, but type-checked and parameterized - a popular alternative to a full ORM.
Migrations: version control for your schema
A schema is never finished - you add a column, a table, an index. A migration is a versioned, ordered script that records one such change. Checked into git and applied by a tool, migrations guarantee every environment - your laptop, staging, production - has the same structure, and that nobody edits production by hand.
-- 0007_add_signup_date.sql
ALTER TABLE customers ADD COLUMN signup_date DATE;
A migration usually has an up (apply) and ideally a down (revert) step, so a bad change can be rolled back. Tools include Flyway, Liquibase, Alembic (Python), Rails migrations, Prisma Migrate, and Atlas - many built into the ORM.
For a live system you cannot just rename a column out from under running code. The 2026 standard is the expand-contract pattern for zero-downtime changes: add the new shape, migrate data and deploy code that writes both, then drop the old shape once nothing uses it. Declarative-schema tools (Atlas, Prisma) increasingly generate these steps for you.
Quick quiz
ORMs and migrations
4 questions1When is dropping from an ORM to raw SQL most justified?
2What problem do ORMs make especially easy to introduce?
3What is the point of a migration?
4How do you rename a column on a live system without downtime?
Connections and serverless - why opening a database connection is expensive, how pooling fixes it, and where databases run in 2026.