You probably don't need query builders

Query builders and ORMs are being reevaluated against hand-written SQL, with many engineers weighing composability and safety against complexity and performance pitfalls. Proponents of builders highlight reusable components, reduced risk of SQL injection, and easier handling of dynamic filters and joins, especially in larger or fast-changing codebases. Critics counter that naive patterns can confuse query planners, overload scarce database CPU, and obscure what the database is actually doing, arguing for simpler parameterized SQL plus targeted abstractions or views where appropriate.

Composability and Reuse

  • Many argue query builders shine for composability: you can define partial queries and reuse them instead of copy‑pasting SQL or maintaining many similar files.
  • Others warn that a “collection of interdependent composable builders” can degrade into complex, overlapping components over years, becoming harder to reason about than a single complex SQL file.

ORMs vs Raw SQL vs Builders

  • Some prefer ORMs (e.g., ActiveRecord, Entity Framework, SQLAlchemy) for rapid prototyping, dynamic UIs, and avoiding N+1 queries, with escape hatches for raw SQL when needed.
  • Critics say ORMs often generate “OK but not optimal” SQL and can hide important database concepts from developers who don’t understand SQL.
  • Several commenters dislike the specific Rust builder shown in the article, calling it string‑builder‑like, hard to read, and a poor representative of query builders in general.

Dynamic Queries, Optional Filters, and Joins

  • A major pain point is building dynamic filters and optional joins (e.g., faceted search, user-driven filters, complex relationships).
  • Some say “anyone can string‑concat simple queries,” but complex optional joins rapidly become unmanageable without builders or an ORM‑style abstraction.
  • Pattern of “AND ($param IS NULL OR column = $param)” is debated: convenient for dynamic filters but potentially harmful for query plans.

Performance and Query Planning

  • Several raise concerns about “catch-all” parameterized queries, especially with prepared statements and SQL Server’s or Oracle’s plan caching and parameter sniffing.
  • Others note that with certain schemas (e.g., selective primary key in WHERE) and specific databases (e.g., Postgres with custom plans), performance can be acceptable, but emphasize context‑dependence.
  • There’s extended debate on whether splitting queries into many smaller calls vs one big join is better; consensus is “it depends” on data size, schema, and workload.

Security and SQL Injection

  • Strong warnings against concatenating SQL fragments, especially for user‑driven queries (search, GraphQL‑like APIs).
  • Builders and parameterization are seen as crucial for preventing injection; misuse (e.g., interpolating identifiers) still introduces vulnerabilities.

Where to Put Logic: DB vs Application

  • One camp advocates “do it in the DB if it can reasonably be done there,” emphasizing constraints and indexes.
  • Another warns that overloading the DB with conditional logic and heavy processing can burn scarce DB CPU and create “noisy neighbor” issues; simple filtering and branching may belong in the app.

Tooling, DX, and Miscellaneous

  • Mentions of named-parameter helpers, string‑interpolation‑based SQL APIs, CTEs, and views as ways to regain composability without full builders.
  • Some like raw SQL files for clarity and debugging; others see them as an anti‑pattern that doesn’t scale.
  • Minor meta discussion about the blog’s hidden scrollbars and accessibility.