ORM Migrations Missing Indexes | Database Performance

Your ORM abstracted away the database complexity you thought was gone. But it also abstracted away the performance problems. Here's what you're actually missing.

Your ORM Is Lying to You: How Missing Database Indexes Hide in Plain Sight — theAIcatchup

Key Takeaways

  • ORMs create foreign keys without automatically indexing them, causing silent performance degradation at scale
  • Developer abstraction from raw SQL has made database visibility optional—until performance problems force you to look
  • Tiger SQL solves this by visualizing Postgres schemas and flagging missing indexes before they hit production
  • The deeper lesson: every abstraction needs a visibility tool to prevent systemic blind spots

Your API just tanked. Users are furious. And somewhere in a 4-hour debugging session, you’ll discover the culprit wasn’t your code—it was something your ORM never told you about in the first place.

This is the hidden cost of ORM abstraction. When tools like Prisma and Drizzle handle schema migrations, they’re solving one problem elegantly while creating another silently. They’ll spin up foreign keys without hesitation. But indexes? Those get left as an afterthought, buried in the database layer where developers almost never look.

For Jackson Kasi, a developer working with modern TypeScript ORMs, that moment of discovery was brutal. A missing index on a single foreign key column stretched a 4-hour debugging sprint into what should’ve been a 10-minute fix. At scale, this isn’t just frustrating—it’s economically destructive.

The Architecture Problem: Abstraction That Hides the Foundation

Here’s what’s actually happening under the hood.

When you define a relationship in Prisma or similar tools, you’re writing clean, readable TypeScript. The ORM translates that into SQL migrations. It creates the foreign key constraint without breaking a sweat. But—and this is the part nobody talks about—creating a foreign key doesn’t automatically create an index on that foreign key column.

“Because developers only look at their schema.ts file, they never visually spot the missing index.”

That’s the gap. The ORM is doing its job (enforcing referential integrity via constraints), but it’s not doing the database optimization job. Those are two different things. A foreign key enforces rules. An index enforces speed. Without the index, Postgres has to scan the entire Orders table every single time you query for a user’s orders. One thousand rows? Fine. Ten million rows? Your database is now doing sequential scans at massive computational cost.

The developer doesn’t see this because the developer isn’t looking at the database. They’re looking at TypeScript. The two worlds have drifted so far apart that critical performance infrastructure becomes invisible.

Why This Happens—And Why It Matters More Than You Think

This isn’t a Prisma or Drizzle bug. It’s a philosophy problem.

ORMs exist to reduce the cognitive load of SQL. They succeed wildly at that goal. But success in one dimension created blindness in another. When you stop thinking about the database as a thing you maintain, you start building on top of abstractions you don’t understand. The schema.ts file becomes your source of truth. The actual database becomes a black box that “just works” until it doesn’t.

The scary part? This pattern scales. At 1,000 users and 100,000 orders, nobody notices. At 10 million orders, you’re running against a wall. By then, the codebase is massive, the team has grown, and the performance debt has calcified. You’re not fixing an index—you’re refactoring architecture under pressure.

And it’s preventable. Totally preventable.

How Missing Indexes Actually Break Things

Let’s be concrete about the mechanics, because the abstraction hides them so effectively.

When you run a query like SELECT * FROM orders WHERE user_id = 123, Postgres has two options. Option one: use an index to look up the user_id directly (fast, logarithmic time). Option two: scan every row in the Orders table until it finds matches (slow, linear time). Without an index, Postgres defaults to the scan. At scale, that scan locks resources, blocks other queries, and creates cascading latency across your entire system.

The ORM doesn’t warn you because it doesn’t know it’s supposed to. The migration runs clean. Tests pass. You ship to production. Three weeks later, traffic spikes and your monitoring lights up like a Christmas tree.

This is why visibility matters so much. If you can see your schema—really see it, visually mapped out with all the indexes marked—you catch these problems before deployment. But the ORM made visibility optional. That was the trade-off for developer speed.

The Open Source Answer: Tiger SQL and Database Introspection

Kasi’s solution to this problem was to build one.

Tiger SQL is an open-source PostgreSQL visualizer that does something radical: it makes your actual database visible. You paste your schema (or connect your database directly) and it renders the relationships as a visual entity-relationship diagram. But the real power is in what comes next—AI-assisted analysis that flags missing indexes before they hit production.

The tool lives in your browser or local environment. No cloud dependency. No vendor lock-in. No enterprise paywall. Just a straightforward answer to a straightforward problem: developers stopped looking at their databases, so we built something that makes databases impossible to ignore.

It’s lightweight. It’s free. And it solves the exact problem that emerges when you let abstractions hide the thing they’re abstracting.

The timing matters here too. Developers are increasingly frustrated with the complexity tax of modern stacks. Tools that reduce friction—that give you power without ceremony—are gaining traction. Tiger SQL fits that pattern. It’s not trying to be another enterprise database platform. It’s trying to close one specific gap in the developer workflow: the moment when someone realizes they didn’t understand their own schema.

The Broader Implication: Abstractions Need Visibility

This problem extends beyond indexes.

Every abstraction in software engineering creates a visibility debt. Rails migrations made database changes feel like code changes. Kubernetes abstracted away servers. Cloud functions abstracted away infrastructure. Each trade-off bought developer velocity in exchange for reduced visibility into what’s actually running.

These trades are net-positive for most use cases. But they create systemic blind spots. You need tooling that lets you peek behind the abstraction without throwing the abstraction away. Tools like Tiger SQL, or even simple schema visualization in your IDE, are essentially reminders that the layer you’re building on top of still exists and still needs maintenance.

The developers who’ll dominate over the next five years won’t be the ones who master every abstraction. They’ll be the ones who understand what’s hidden underneath and know when to look.


🧬 Related Insights

Frequently Asked Questions

How do I know if my database is missing indexes?

Run SELECT * FROM pg_stat_user_indexes; in PostgreSQL to see what indexes exist. Compare against your schema definition. Look for foreign key columns without corresponding indexes—those are your culprits. Tools like Tiger SQL automate this scan and flag problems visually.

Will my ORM automatically create indexes in the future?

Maybe, but don’t bet on it. Prisma and Drizzle are improving, but index creation requires understanding your query patterns and access paths—things ORMs can’t reliably infer. You need human judgment. At minimum, make index creation an explicit part of your migration process, not an afterthought.

Is Tiger SQL free to use in production?

Yes. It’s open-source and runs locally or in your browser. There’s no vendor dependency, no usage limits, no enterprise tier. Fork it from GitHub, run it yourself, and you’re done.

Can I use this with databases other than PostgreSQL?

Tiger SQL currently focuses on Postgres, but the concept—visual schema inspection with AI-assisted optimization—is portable. MySQL, MariaDB, and other relational databases all suffer the same indexing blindness problem.

Marcus Rivera
Written by

Tech journalist covering AI business and enterprise adoption. 10 years in B2B media.

Frequently asked questions

How do I know if my database is missing indexes?
Run `SELECT * FROM pg_stat_user_indexes;` in PostgreSQL to see what indexes exist. Compare against your schema definition. Look for foreign key columns without corresponding indexes—those are your culprits. Tools like Tiger SQL automate this scan and flag problems visually.
Will my ORM automatically create indexes in the future?
Maybe, but don't bet on it. Prisma and Drizzle are improving, but index creation requires understanding your query patterns and access paths—things ORMs can't reliably infer. You need human judgment. At minimum, make index creation an explicit part of your migration process, not an afterthought.
Is Tiger SQL free to use in production?
Yes. It's open-source and runs locally or in your browser. There's no vendor dependency, no usage limits, no enterprise tier. Fork it from GitHub, run it yourself, and you're done.
Can I use this with databases other than PostgreSQL?
Tiger SQL currently focuses on Postgres, but the concept—visual schema inspection with AI-assisted optimization—is portable. MySQL, MariaDB, and other relational databases all suffer the same indexing blindness problem.

Worth sharing?

Get the best AI stories of the week in your inbox — no noise, no spam.

Originally reported by Dev.to

Stay in the loop

The week's most important stories from theAIcatchup, delivered once a week.