From ORM to pGenie: A 14-Year Journey to SQL-First Database Development
#Backend

From ORM to pGenie: A 14-Year Journey to SQL-First Database Development

Tech Essays Reporter
4 min read

Nikita Volkov's evolution from building an ORM to creating pGenie reveals why treating the database as the single source of truth transforms how we build applications.

In 2012, I was a typical web developer building CRUD applications with the confidence that performance problems were for "later" and that migrations were unnecessary complications. That year, I built SORM—an ORM framework for Scala that exchanged mutable database objects as immutable values. It felt novel, gained traction, and for a while seemed like success. Then reality hit hard.

Every non-trivial query exposed the limits of the DSL. Keeping the code model in sync with the real database schema became a constant headache. I was essentially inventing a worse version of SQL just to make the integration "safer." By 2014, I stopped development. By 2016, I killed support entirely. The lesson was brutal but clear: abstracting over SQL is usually a mistake.

This failure led me to hasql in 2014—a PostgreSQL driver that embraced raw SQL and provided composable abstractions supporting it. Hasql became one of the two main Postgres drivers in the Haskell ecosystem and the most efficient one. But even with this solid foundation, something was still missing. Users had to accompany every query with hand-rolled codecs, and SQL strings lacked validation.

In 2019, I shipped hasql-th—a compile-time SQL syntax checking library based on a port of the PostgreSQL parser. It made things simpler and safer, but we still needed queries validated against the actual schema. I watched projects over the years try to solve this by introducing compile-time database connections, but that always felt like a hack that made builds unreproducible. I wanted a solution that could be contained in code in a repository without infrastructure dependencies.

Then came the insight that changed everything: Migrations + Queries = Database API. If you treat your Postgres server like a microservice, then migrations become the contract (like an OpenAPI schema for REST), and queries become the operations. Your application is just a client of that API. The database is primary. The application code is secondary. This is the DB-First (or SQL-First) approach.

Suddenly everything clicked. The schema lives in SQL migrations. The queries live in .sql files. All of that gets checked into a repository and becomes subject to development, testing, and review. Everything else—types, encoders, decoders, index recommendations—can be automatically derived and safely integrated into codebases with the help of type-checking compilers.

From 2022 to 2026, I first released pGenie as a SaaS experiment. Companies didn't like sending their schemas and queries to a third party. Fair enough. So in 2026, I open-sourced it completely and switched to an OSS+Consulting business model: github.com/pgenie-io/pgenie.

pGenie is a simple CLI. You point it at your migrations/ and queries/ folders. It spins up a real PostgreSQL container, recreates the schema by running migrations, prepares queries, analyzes the information schema, and generates 100% type-safe client code for various targets via plugins. Currently Haskell, Rust, and Java are fully supported as such plugins.

What pGenie Actually Gives You:

  • Zero boilerplate type-safe SDKs
  • Fidelity to advanced Postgres features (JSONB, arrays, composites, multiranges, extensions, etc.) and queries of any complexity
  • Decentralized code generators written in safe, reproducible Dhall
  • Signature files that catch schema drift at build time
  • Automatic index recommendations and sequential-scan warnings

The full side-by-side of source SQL and the generated client code for Haskell, Rust, and Java is in the demo repo—try it yourself.

Why This Matters Now (Especially in the AI Era) LLMs are fantastic at writing SQL. They are not that great at ensuring it still works after your next migration. pGenie closes that gap: AI writes the query → pGenie verifies it against the real schema → you get a predictably structured type-safe SDK in seconds. SQL-First + AI = maximum velocity with zero surprises.

Ready to stop fighting your database? Study the docs: pgenie.io/docs Ask questions and share ideas: github.com/pgenie-io/pgenie/discussions Give it a ⭐ on GitHub: github.com/pgenie-io/pgenie

The journey from building an ORM to creating pGenie taught me that the query itself is the integration point—not the application model, not the table row structure. The query determines the structure of parameters it needs and what it returns. Trying to reuse "row types" across queries only creates hidden dependencies and future breakage. By treating the database as the single source of truth, we finally align our development practices with the reality of how modern applications actually work.

Comments

Loading comments...