Open-source project
seancorfield/honeysql avatar
seancorfield/honeysql

HoneySQL 2.7: Building SQL from Clojure Data

Turn Clojure data structures into SQL

1,929 stars181 forksClojureNOASSERTION

At a glance

What is it?
HoneySQL 2.7 represents SQL statements as Clojure maps and SQL expressions as vectors, giving Clojure developers a programmatic alternative to assembling query strings. It suits JVM, ClojureScript, Babashka, Jolt, and let-go projects that need SQL generation with dialect support.
Who is it for?
HoneySQL 2.7 is appropriate for Clojure developers who want query composition to remain ordinary data manipulation and for applications that need more than one SQL dialect. It is a poor fit for teams that require hand-written SQL, have only a few fixed queries, or cannot accept a custom library licence.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Clojure, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why HoneySQL represents queries as Clojure data

HoneySQL addresses the difficult and error-prone part of constructing SQL inside application code: keeping clauses, conditions, values, and formatting in agreement. Its stated purpose is to build queries programmatically, including at runtime, without concatenating SQL strings. Instead of treating a statement as an opaque string, the library models it with Clojure data structures that can be composed, inspected, passed through functions, and transformed.

The primary audience is Clojure developers writing data access code, but the runtime coverage extends beyond ordinary server-side Clojure. HoneySQL 2.7 requires Clojure 1.10.3 or later. The README also lists support for recent versions of ClojureScript, Babashka, Jolt, and `let-go`. That makes the query model potentially available in JVM services, browser code through ClojureScript, and scripting environments, subject to the capabilities of the selected runtime and SQL adapter.

HoneySQL does not replace a database driver, connection pool, or migration tool. It addresses SQL construction, not database connectivity or schema management. A team looking for a complete data access layer still needs other components. HoneySQL's narrower purpose is to convert Clojure data into SQL text and associated values, after which the application can pass the result to its database layer.

The library is particularly relevant when query shape changes at runtime. Hard-coded SQL works well for fixed statements, but conditions assembled from optional filters, selected columns, ordering rules, or pagination settings can become difficult when represented only as string fragments. HoneySQL gives those choices a structured form before rendering. The README does not claim that this design eliminates every SQL injection or database error, and it should not be read as doing so. Parameter handling and identifier handling remain integration concerns that depend on how the generated query is passed to the database library.

HoneySQL maps, expression vectors, and dialect formatting

HoneySQL's documented representation has two central forms. SQL statements are built on hash maps, while SQL expressions and function calls can be represented as vectors. This lets ordinary Clojure functions manipulate a query without first parsing SQL text. Adding a predicate, selecting another column, or choosing a different sort order can be expressed as a data transformation rather than as string concatenation.

The README begins its structural example with a `:select` query map. In that example, `:select` identifies the clause and the following vector contains column keywords. The README excerpt does not show the rest of the statement, so the exact construction and formatting call should be taken from the linked Getting Started documentation rather than inferred here. HoneySQL directs readers to that page because maps form the statement DSL and vectors participate in its expression syntax.

The `honey.sql` namespace exposes the core query model. The `honey.sql.helpers` namespace provides helpers including `select`, `select-distinct`, `from`, `join`, `left-join`, `right-join`, `where`, `group-by`, `having`, `order-by`, `limit`, `offset`, `insert-into`, `update`, `delete-from`, and `truncate`. These helpers make common clauses easier to construct while retaining the data-oriented representation.

HoneySQL 2.x includes SQL dialect support out of the box. The README says the project will add vendor-specific language features over time. That is a meaningful difference from legacy 1.x, which the README contrasts with the newer dialect model. Version 2.x also provides a simpler method for extending the DSL. Users should still check the documentation for exact dialect names and supported syntax before depending on a particular vendor feature.

Rendering is separate from query description. The documented `:inline true` option generates pretty SQL with inline values for copying into a SQL tool. The `:pretty true` option adds newlines between clauses in generated SQL strings. The README does not document a general fallback for passing literal SQL through the DSL, so applications that require uncommon statement forms should confirm compatibility before conversion.

Clojure setup and the first HoneySQL query

The Clojars coordinate is `com.github.seancorfield/honeysql`, and the README badge displays version `2.7.1479`. The README does not include a dependency declaration in its shown usage section, so this tutorial does not invent a `deps.edn` or Leiningen entry. Add the project to the build configuration already used by the application, then require the core and helper namespaces.

In a Clojure namespace, import `clojure.core` with an exclusion list before referring the helpers. The exclusion matters because `honey.sql.helpers` defines names such as `filter`, `for`, `group-by`, `into`, `partition-by`, `set`, and `update`, which overlap with `clojure.core`. The README recommends referring only to selected helpers or retaining access to the core versions through the `c` alias.

clojure
(refer-clojure :exclude '[assert distinct filter for group-by into partition-by set update])
(require '[honey.sql :as sql]
         '[honey.sql.helpers :refer :all :as h]
         '[clojure.core :as c])

After this require form, `honey.sql` is available as `sql`, the HoneySQL helpers are available under `h`, and the non-conflicting `clojure.core` functions remain available through `c`. The exclusions prevent the helper definitions from replacing those core functions in the current namespace.

ClojureScript does not support `:refer :all`, according to the README, so a browser-oriented setup refers to specific helper names instead. This list includes the query, join, grouping, ordering, pagination, write, and deletion helpers documented by the project.

clojure
(require '[honey.sql :as sql]
         '[honey.sql.helpers :refer [select select-distinct from
                                     join left-join right-join
                                     where for group-by having union
                                     order-by limit offset values columns
                                     update insert-into set composite
                                     delete delete-from truncate] :as h]
         '[clojure.core :as c])

The first concrete use is to construct a statement map and format it through the API documented in the Getting Started guide. Because the README excerpt omits the complete first-use example and its formatting invocation, a working call cannot be copied reliably from that section alone.

Runtime constraints and failures in HoneySQL 2.7

The clearest runtime constraint is the minimum Clojure version. HoneySQL 2.7 requires Clojure 1.10.3 or later, while the README says earlier HoneySQL releases support Clojure 1.9.0. An application pinned to Clojure 1.9 cannot adopt 2.7 directly. The legacy 1.x and 2.x lines also use different group IDs and namespaces, so a migration must account for both dependency coordinates and source namespace changes rather than assuming a drop-in replacement.

The helper namespace also introduces naming friction in Clojure. Importing its names without exclusions can replace familiar `clojure.core` functions. The documented approach is to exclude conflicting names or refer only to chosen helpers. That keeps access to the core versions explicit, although it requires more deliberate namespace setup than a helper library with non-conflicting names.

Multi-runtime support does not establish that every query operation behaves identically in Clojure, ClojureScript, Babashka, Jolt, and `let-go`. The README names those runtimes as supported but does not enumerate runtime-specific exceptions in the shown text. Dialect support has a related boundary: dialects are included, but the README does not list every supported vendor feature. Code that depends on niche syntax should be checked against HoneySQL's dialect documentation.

HoneySQL is the wrong abstraction when an application requires exact hand-authored SQL comments, an unusual procedural statement, or database syntax that does not fit the data model. Converting a small static SQL file into DSL calls can add complexity without delivering useful flexibility. HoneySQL fits better where clauses are naturally assembled from Clojure values, such as optional predicates or selectable columns.

HoneySQL 2.7 releases, CI snapshots, and upgrades

The repository is not archived, and its last push was on 2026-10-11. Recent releases include `v2.7.1479` on 2026-09-21, `v2.7.1437` on 2026-08-02, and `v2.7.1425` on 2026-07-26. This release history and the recent push show current development activity, although the project uses a version scheme that differs from semantic versioning.

HoneySQL follows `MAJOR.MINOR.COMMITS`. The README says `MAJOR` and `MINOR` provide a rough indication of change size, while `COMMITS` is an ever-increasing counter. It explicitly states that the scheme does not follow semantic versioning. As a result, the usual expectation that a major version component always marks a major compatibility break is not dependable here. Upgrades require reading `CHANGELOG.md` and the relevant release documentation rather than relying only on the numbers.

The stated compatibility approach is generally to avoid breaking existing names by moving changed names to new names. This can preserve source compatibility, but it can also leave older names in the API and defer migration decisions. The repository includes `CHANGELOG.md`, `doc/`, and the `develop` branch, which are the relevant places to inspect for API changes.

Every commit to `develop` runs CI, and successful runs publish a `MAJOR.MINOR.9999-SNAPSHOT` build to Clojars. This makes current development code available as a snapshot without requiring a dependency on the latest Git SHA. A production deployment should normally assess numbered releases rather than assuming a snapshot has the same release qualifications.

The repository declares a custom licence that GitHub could not classify. The README does not state the licence permissions or restrictions, so adoption requires direct review of `LICENSE`. Its effect on redistribution, modification, publication, and organizational use cannot be inferred from the `Other` category.

HoneySQL compared with literal SQL and the legacy 1.x DSL

The clearest alternative is direct SQL text used with a Clojure database library. That approach writes SQL in its native syntax and passes strings plus arguments to the database layer. It is easier for developers who prefer reading and editing SQL as SQL, and it avoids adding a translation layer for a small number of fixed statements. Its disadvantage appears when query fragments must be selected or rearranged repeatedly, because string assembly can obscure structure and place more responsibility on every caller.

HoneySQL takes the opposite approach. Statements begin as maps, and vectors participate in expression construction, so ordinary Clojure operations can manipulate query definitions. The trade-off is that developers must learn its DSL and consult the syntax it supports. Exact SQL that does not fit the model can also be less natural than literal text. The README does not document a literal-SQL escape hatch, so users should not assume that arbitrary SQL can bypass DSL translation.

For an existing HoneySQL 1.x codebase, the relevant comparison is between HoneySQL generations rather than between HoneySQL and an unrelated library. The repository provides a dedicated summary of 1.x and 2.x differences and states that both versions can coexist because they use separate group IDs and namespaces. HoneySQL 2.x offers a smaller codebase, a simpler DSL extension path, and built-in dialect support. Coexistence supports gradual migration, but it also adds dependency and namespace management that a new application may not need.

Editorial conclusion

HoneySQL 2.7 is appropriate for Clojure developers who want query composition to remain ordinary data manipulation and for applications that need more than one SQL dialect. It is a poor fit for teams that require hand-written SQL, have only a few fixed queries, or cannot accept a custom library licence. Before adoption, review the `LICENSE` file, confirm that HoneySQL covers the required SQL dialect and Clojure version, and check the Getting Started documentation for the exact formatting API.

Frequently asked questions

What Clojure version does HoneySQL 2.7 require?

HoneySQL 2.7 requires Clojure 1.10.3 or later. The README says earlier HoneySQL versions support Clojure 1.9.0.

Can HoneySQL 1.x and 2.x be used in the same project?

Yes. The README states that 1.x and 2.x use different group IDs and namespaces, allowing them to be used side by side during a gradual migration.

How are SQL queries represented in HoneySQL?

SQL statements are built on hash maps. SQL expressions and function calls can be represented as vectors, according to the README.

Does HoneySQL support SQL dialects?

The README states that HoneySQL 2.x supports SQL dialects out of the box and is intended to gain further vendor-specific language features over time.

Which runtimes does HoneySQL 2.7 support?

The README lists recent versions of ClojureScript, Babashka, Jolt, and `let-go`. It does not identify exact runtime versions in the displayed section.

What licence does HoneySQL use?

GitHub classifies the licence as Other and links to a custom licence file. The README does not describe its permissions or restrictions, so `LICENSE` is the controlling source.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. seancorfield/honeysql on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/seancorfield-honeysql.svg)](https://hysenlabs.com/projects/seancorfield-honeysql)

Was this useful?