Lacinia GraphQL Engine for Clojure Backends
GraphQL implementation in pure Clojure
At a glance
- What is it?
- Lacinia is a backend-agnostic GraphQL query execution engine written in Clojure. It supports EDN or GraphQL SDL schemas, asynchronous execution, subscriptions, and resolver functions, while leaving HTTP integration to separate libraries.
- Who is it for?
- Adopt Lacinia when a Clojure service needs a GraphQL contract between clients and application data, especially when resolvers can map naturally to Clojure functions. Do not choose it as a complete web server, database layer, or maintenance replacement without checking the custom LICENSE and verifying integration with the chosen HTTP pipeline.
- 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 142 days 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
Lacinia's Contract-First Clojure Design
Lacinia solves the problem of exposing application data through a GraphQL API without prescribing a web framework or data-access technology. The README positions it as roughly analogous to Facebook's official reference JavaScript implementation, graphql-js, but for a Clojure environment. Its boundary is deliberate: clients submit GraphQL operations, Lacinia parses and executes them against a compiled schema, and application code supplies the values returned by field resolvers.
The intended audience is Clojure backend developers who want to define API behavior as data and implement behavior as ordinary functions. A schema describes available fields, arguments, types, enums, and other GraphQL elements. It does not provide database records, make HTTP requests, or manage a listening port. Resolvers handle those application concerns. This makes Lacinia suitable for services that already have an HTTP pipeline, as well as projects that want to separate GraphQL execution from transport code.
The library is not an Object Relational Mapper. A resolver may call a database or another service, but that choice remains in application code. The repository includes source, tests, documentation, resources, Java support, build files, and a `codegen.sh` script, indicating a substantial library rather than a small adapter around an existing GraphQL engine. No GitHub releases are listed, so release history is not available from the repository metadata.
EDN, SDL, and Resolver Execution
Lacinia accepts an EDN-based schema language or GraphQL's Interface Definition Language. The EDN representation uses nested maps, keywords, lists, and custom forms such as `non-null`, which fits Clojure data structures directly. A schema can define enums, objects, fields, arguments, and default values. The README's example defines `:Query`, `:Human`, and `:Droid`, including a `hero` field with an episode argument and a `droid` field with an id argument.
A schema alone does not supply data. A field resolver receives the application context, a map of argument values, and the resolved parent value. The resolver returns data consistent with the field's declared GraphQL type, often a Clojure map, record, list, vector, or set. Lacinia then selects the requested fields from those values. In production, the README says a resolver could query a database or call another web service, but it does not define either integration.
The execution path is assembled during application startup. `inject-resolvers` associates resolver functions with schema fields, and `schema/compile` validates the schema, applies defaults, and prepares it for query execution. The compiled schema can then be passed to `execute` with a query document and application-specific values. The README describes this as a one-time startup step. This is a useful separation for services because schema preparation does not need to happen for every request.
Lacinia documents support for interfaces, unions, enums, input objects, custom scalars, fragments, introspection, and subscriptions. Union definitions may use a leading vertical bar before the first member. These are GraphQL language and execution capabilities, not evidence that Lacinia provides schema governance, migrations, query persistence, or operational monitoring.
Installation, Schema Compilation, and First Execution
The repository's dependency preparation step is required because Lacinia uses precompiled ANTLR parsers that must be built before use. The README gives this command:
clojure -X:deps prepAfter preparing the library, a project can define a schema and compile it during startup. The following example follows the repository's README and reads `schema.edn`, injects the named resolvers, and compiles the result.
(require '[clojure.edn :as edn]
'[com.walmartlabs.lacinia.util :refer [inject-resolvers]]
'[com.walmartlabs.lacinia.schema :as schema])
(def star-wars-schema
(-> "schema.edn"
slurp
edn/read-string
(inject-resolvers {:Query/hero get-hero
:Query/droid (constantly {})})
schema/compile))The reader should see a compiled schema value bound to `star-wars-schema`. The schema file itself must contain the EDN type definitions. Lacinia does not provide the application's database or service connections in this example.
Execution is performed through the `execute` function. The README shows a Ring-style handler that reads a `query` query parameter and serializes the returned EDN as JSON:
(require '[com.walmartlabs.lacinia :refer [execute]]
'[clojure.data.json :as json])
(defn handler [request]
{:status 200
:headers {"Content-Type" "application/json"}
:body (let [query (get-in request [:query-params :query])
result (execute star-wars-schema query nil nil)]
(json/write-str result))})This is an execution example, not a complete HTTP server. Lacinia itself does not know about the web tier. The companion `lacinia-pedestal` project supplies HTTP support, including GraphQL subscriptions, while `duct-lacinia` is described as an externally developed Duct integration. A first real use therefore consists of adding Lacinia to an existing Clojure pipeline, compiling the schema at startup, and passing incoming GraphQL documents to `execute`.
Subscriptions and HTTP Integration Boundaries
Lacinia documents full GraphQL subscription support, but the query execution shown in the README is request-oriented and does not explain how a subscription connection is established, authenticated, or disconnected. The companion `lacinia-pedestal` library is identified as providing full HTTP support, including GraphQL subscriptions, for Pedestal. This boundary matters when evaluating Lacinia for production use. Query execution and subscription transport are related features, yet the README assigns the complete HTTP integration to a companion project.
The same separation applies to common server concerns. The README does not document TLS configuration, request size limits, persisted queries, batching, tracing, caching, schema registry integration, or rollback of a schema deployment. Those omissions do not establish that Lacinia lacks extensions in its broader documentation, but they mean this repository page cannot support a claim that the core library handles them.
Lacinia can be inserted into any Clojure HTTP pipeline according to the README. That statement describes flexibility at the integration boundary, not a promise that every pipeline has equal support. Pedestal has a named companion library, and Duct has an externally developed integration. A team using another Clojure server would need to map its request and response conventions to `execute` and determine separately how subscription streams are delivered.
Where Lacinia Is the Wrong Tool
Lacinia is the wrong choice when the project needs a ready-made GraphQL endpoint rather than an execution engine. It does not present itself as an HTTP server, and the documented integration requires another library or application pipeline. It is also the wrong choice when the requirement is primarily ORM behavior. The README explicitly rejects that interpretation, so database mapping, connection management, and migration tooling must be supplied separately.
The pure Clojure focus may also be a constraint for teams that do not want to maintain a schema compilation step or write resolvers as Clojure functions. The required parser preparation command and startup compilation are part of the documented path. The repository provides no GitHub releases, so a team that requires a published release stream would need to investigate packaging and upgrade procedures outside the information presented here.
The custom license is another adoption check. GitHub classifies it as `Other`, and the repository points to the `LICENSE` file. Its permissions, obligations, and compatibility with an organization cannot be inferred from the label alone. A procurement or legal review must inspect that file before shipping the library.
GraphQL Engine Alternatives and Upgrade Cost
The README names graphql-js as the official reference JavaScript implementation and describes Lacinia as roughly analogous to it. The practical difference is ecosystem and host language. graphql-js is a JavaScript implementation associated with the reference implementation, while Lacinia is written in pure Clojure and is designed to fit Clojure's EDN, keywords, functions, and persistent data structures. Lacinia therefore favors a Clojure application that wants GraphQL execution without moving the service's implementation language to JavaScript.
The companion integrations provide a separate comparison point for web stacks. `lacinia-pedestal` targets Pedestal and documents subscription support, while `duct-lacinia` offers similar capability for Duct. These are not described as equivalent execution engines with identical APIs; they are transport integrations around Lacinia. A team should compare the integration's HTTP and subscription behavior rather than infer those features from the core library alone.
Maintenance information is limited. The repository is not archived, and its last push was on 2026-06-03. There are no GitHub releases listed, so there is no release cadence or upgrade path in the repository metadata. The ANTLR parser preparation requirement may add a build concern, and schema compilation is an application startup task. Upgrading requires checking the project version, parser compatibility, schema behavior, and changes to the custom `LICENSE` file.
Editorial conclusion
Adopt Lacinia when a Clojure service needs a GraphQL contract between clients and application data, especially when resolvers can map naturally to Clojure functions. Do not choose it as a complete web server, database layer, or maintenance replacement without checking the custom LICENSE and verifying integration with the chosen HTTP pipeline. The first checks should be subscription delivery, parser preparation, resolver behavior, and the exact terms in LICENSE.
Frequently asked questions
How do I install Lacinia as a Clojure dependency?
The README says to run `clojure -X:deps prep` when using Lacinia as a dependency. This prepares the precompiled ANTLR parsers required by the library.
Does Lacinia include HTTP server support?
No. Lacinia is described as backend-agnostic and does not know about the web tier. The README points to `lacinia-pedestal` for Pedestal support and `duct-lacinia` for Duct support.
How are GraphQL fields connected to application data?
A schema declares fields and arguments, while field resolver functions receive the application context, arguments, and parent value. Resolvers return maps, records, lists, vectors, or sets that Lacinia uses to produce the requested response.
Official sources
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.
[](https://hysenlabs.com/projects/walmartlabs-lacinia)Was this useful?