Absinthe compiles your GraphQL schema into Elixir macros before the first request
The GraphQL toolkit for Elixir
At a glance
- What is it?
- Absinthe is the Elixir implementation of the GraphQL spec, aimed at teams running Phoenix and Plug endpoints. Its distinguishing move is compile-time schema verification and a pipeline you can rebuild phase by phase, at the cost of a macro-heavy DSL and a stale version constraint in its own install snippet.
- Who is it for?
- Adopt Absinthe if your Elixir service already speaks Phoenix or Plug and you want one pipeline you can inspect and replace piece by piece. Skip it if your team wants a plain schema file with no macro layer, or if you cannot commit to reading the CHANGELOG for version jumps.
- 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 18 days ago.
- What is it written in?
- Mainly Elixir, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- absinthe-graphql/absinthe4,403 ★ · +1
| Repository | 2026-09-23 | 2026-11-13 |
|---|---|---|
| absinthe-graphql/absinthe | 4.4k | 4.4k |
1 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Schemas are macros, so a typo in a field name fails at compile time
Most GraphQL servers in other languages read a schema document at boot and report problems when a query arrives. Absinthe inverts that. A schema is written with macros, and those macros build and verify their own structure while the project compiles. The README says this prevents runtime errors.
The goals list behind that choice names five aims, and one of them is a focus on robustness and production-level performance. The README also promises an idiomatic API and extensibility built from small parts that each do one thing.
That single design choice explains most of what follows. It also explains why Absinthe feels unlike a configuration file. Your schema is Elixir source. It compiles into beam code alongside the rest of your application, which is why the project can promise production-level performance in its own goals list without a schema parsing step sitting in front of every request.
The audience is narrow and specific: teams already writing Elixir who are standing up a Phoenix or Plug endpoint and have decided that a GraphQL front door beats a proliferation of REST routes. If your service is not on the BEAM, nothing here applies to you.
The query pipeline is a list you can edit, phase by phase
The parser, the validation rules, and the resolution logic are not sealed inside a black box. Absinthe lets you add, swap, or remove any of them, and the README makes a stronger claim: even on a per-document basis. A document you trust can skip the checks you would otherwise run on a public one.
Resolution itself has three extension points worth knowing by name. Asynchronous field resolution lets slow fields return without blocking siblings. Batched field resolution exists to address N+1 query problems, where a list of records fires one identical lookup per row against your database. A resolution plugin system sits on top of both.
On the safety side, complexity analysis with configurable limiting gives you a ceiling on expensive documents, and support for precompiled documents lets you accept a known query set and reject custom ones. That combination is what makes the library usable behind a public endpoint rather than only inside a trusted network.
Adding absinthe to deps, and the version trap in that snippet
Installation comes from Hex.pm, and the README shows the dependency entry to add to your mix file.
def deps do
[{:absinthe, "~> 1.7.0"}]
endRead that constraint before you copy it, because the most recent published release is v1.12.0 from 2026-09-02 while the snippet still pins the 1.7 series, and upgrade steps between versions live in the CHANGELOG file at the repository root rather than in prose. Absinthe also requires Elixir 1.10 or higher, which is the other version fact to check against your own project.
Complex analysis and precompiled documents are opt-in boundaries, not defaults
Compile-time verification covers the schema you wrote. It does nothing for the document a stranger sends you. That boundary is where the two safety features matter, and where the limits of the compile-time story show.
The README lists complexity analysis and configurable limiting but does not say what the default limit is, and the compile-time guarantee that made the team choose Absinthe in the first place says nothing about the load such a document can create. Asynchronous field resolution has the same character: it is available, and the README does not document a default value for it, so whether it is on in your endpoint depends on how you built the pipeline.
Batched resolution deserves the same scrutiny from the other direction. It exists to collapse repeated identical lookups, but the README does not describe how you mark a field as batched or what the batching window is. If your data access does not fit that shape, no part of the compile-time story will save the query count.
camelCase for clients, snake_case in the module, adapters for everything else
Naming is where the DSL reaches past the server. Schemas are written in Elixir `snake_case`, and Absinthe translates to `camelCase` transparently for clients that expect it. Where that default does not match your contract, the project does not force a fork: you write a small adapter that defines your own translation.
That is a design position worth naming. Rather than growing configuration for every possible naming convention, Absinthe keeps one default and one documented escape hatch. The cost falls on whoever needs the fourth convention, since the adapter is yours to write and to test.
Frontend and backend integration is handled by specialization rather than by abstraction. On the server side there is dedicated support for Phoenix and Plug. On the client side there is dedicated support for Relay. Other frontend frameworks and GraphQL clients still work, just without the dedicated path. If you are not running Phoenix or Plug, you are in that unlisted remainder from the first request.
Schema metadata extraction hides behind mix help, not a CLI
Absinthe ships Mix tasks for extracting schema metadata, and the README does not enumerate them. Instead it tells you to run `mix help` in your project and look for tasks starting with `absinthe`. That is the whole discovery procedure, and it is worth doing before you design anything: the shape of what you can extract decides whether your client codegen story works.
Two things are absent from the repository documentation and will not show up in that task list. There is no standalone server binary to run against a schema file, because the schema lives in compiled Elixir modules rather than in a document. And there is no rollback story for a schema change, because a schema here is code, so reverting means reverting a commit. If your team wants a migration path for schema changes separate from your deployment path, that gap has to be closed by your own tooling.
The rest of the repository layout supports the same reading: `guides/` for prose, `priv/` for anything shipped with the release, `benchmarks/` for measurement, `src/` and `lib/` for the implementation, and a `.dialyzer_ignore.exs` at the root, which tells you the type checker is run with an explicit exemption list.
Where Graphene approaches the same problem from the other direction
The alternative design defines schemas as plain data structures at runtime rather than with macros that expand at compile time. Absinthe builds its schema with macros that the compiler checks.
That choice trades a different set of costs. The map-based route keeps the schema inspectable and mutable at runtime, which suits environments where schema shape is partly data. The macro route trades that flexibility for verification before deployment and for code that the BEAM already understands. This repository's README does not compare Absinthe with other GraphQL implementations.
For a service whose schema is stable, written by the same team that owns the endpoint, the compile-time route fits the work. For a codebase where the schema shape is decided at runtime or shared with tooling that expects plain data, the map-based route may fit better.
Editorial conclusion
Adopt Absinthe if your Elixir service already speaks Phoenix or Plug and you want one pipeline you can inspect and replace piece by piece. Skip it if your team wants a plain schema file with no macro layer, or if you cannot commit to reading the CHANGELOG for version jumps. Before writing a single field, check what your existing endpoint looks like: a Plug router already carrying Phoenix means the specialization pays for itself, otherwise you are buying a compile-time DSL for a service that has no transport to plug into. Then pin the version you actually intend to run rather than copying the constraint from the README.
Frequently asked questions
What version of Elixir does Absinthe require?
The README states that Absinthe requires Elixir 1.10 or higher.
How do I install Absinthe in an Elixir project?
Add the dependency to your deps list from the Hex.pm package, then run mix help in your project and look for tasks starting with absinthe.
Does Absinthe support Phoenix and Plug?
Yes. Absinthe includes specialized support for Phoenix and Plug on the backend, and dedicated support for Relay on the frontend.
Can I change the Absinthe query pipeline?
The parser, individual validations, or resolution logic can be added, swapped out, or removed, even on a per-document basis.
How does Absinthe protect against expensive queries?
Absinthe includes complexity analysis with configurable limiting, and support for precompiled documents if you want to prevent custom ones.
How do I convert Elixir field names for a camelCase client?
Schemas are written in snake_case and Absinthe translates transparently to camelCase. For a different convention you write your own translation adapter.
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/absinthe-graphql-absinthe)Star history chart for your README
[](https://hysenlabs.com/projects/absinthe-graphql-absinthe)Was this useful?