Why I Push Back on SQL-Driven Architectures (and When They Still Make Sense)

If there's one architectural debate that seems to resurface in every project, it's whether business logic belongs in the application...

If there's one architectural debate that seems to resurface in every project, it's whether business logic belongs in the application layer or buried deep within the database. My position? I push back—strongly—against SQL-driven architectures that lean heavily on stored procedures and database-side logic.

This isn't a knee-jerk reaction. It's a stance forged from experience.

When business logic lives in stored procedures, it becomes opaque. Tracking execution paths, debugging issues, or even understanding what the system is doing requires diving into a disconnected layer of SQL code. That means context switching for developers, manual version control, and in many cases, a reliance on DBAs for even simple changes. It creates a bottleneck where there doesn't need to be one.

More importantly, it violates the principles of modular architecture. We preach separation of concerns in code but then allow the database to become the execution engine for key business decisions. This makes testing harder, dependency mapping nearly impossible, and onboarding new developers a frustrating exercise in tribal knowledge.

That's not to say stored procedures are always bad. There are valid use cases—especially for highly optimised read operations or legacy system integrations. Sometimes, the best-performing version of a query is one that's been handcrafted and tuned inside the database. And in security-sensitive environments, stored procs can act as a gatekeeper to ensure users can only execute specific data operations.

But those cases are the exception, not the rule.

Modern architectures thrive on clear boundaries, versionable logic, and testable flows. By keeping business logic in code—alongside services, APIs, and handlers—we unlock better tooling, more robust automation, and cleaner separation of concerns. It aligns with the principles of CQRS, DDD, and test-driven development.

In my own work, particularly when strangling legacy systems or designing microservices, I treat stored procedures as a signpost. If I find one, I ask: should this logic live here? Is it here because it needs to be—or because it's always been?

In the end, I'm not anti-database. I'm pro-clarity. And burying your business rules in a layer that few can see, test, or control is rarely the clearest path forward.

Want to discuss this article?

Get in touch with our team.