Biff.graph: A Lightweight Graph Query Layer for Clojure
Biff.graph is a ~600-line library that lets you query your database and derived data as a unified graph, inspired by Pathom but designed to be easier to understand and debug.

Biff.graph is a new library from the Biff Clojure web framework that provides a lightweight graph-based data modeling layer. It lets you structure your data model as a queryable graph, combining database access and derived/business logic into a single, unified interface.
The library is essentially a simplified version of Pathom, but with a much smaller footprint — about 600 lines of code total, with the query execution engine being only 200 lines. The key tradeoff: biff.graph skips the query planning step that Pathom uses, which means some queries may be less efficient, but the codebase is far more approachable for developers who don't need the full power of Pathom.
How It Works
Biff.graph uses a subset of EQL and Datomic pull patterns to describe data shapes. You define "resolvers" — small, independent functions that each handle a specific piece of data. Each resolver has an input query and an output query. The library's query engine then chains these resolvers together to return data in whatever shape you request.
For example, you might define a resolver that fetches a blog post from the database, and another resolver that cleans up the post title by removing emojis. When you query for a post with a clean title, biff.graph automatically calls both resolvers and combines the results.
Key Design Decisions
The library supports batch resolvers and caching, which helps mitigate the lack of query planning. The author, Jacob O'Bryant, created biff.graph because he loved using Pathom but worried it was too complex for Biff's target audience — developers working on smaller projects who might not be familiar with graph data modeling patterns.
Biff.graph is currently in release candidate status (version 2.0.0-rc7) and will remain so until all other Biff 2 libraries are released. Breaking changes are not anticipated.
Practical Usage
The recommended pattern is to autogenerate one resolver per database table, with the input being the primary key and the output including all columns plus join keys for foreign keys. Additional resolvers for derived data can be added gradually as needed. The library integrates with biff.fx for use in Ring request handlers.
Debugging is handled via exception data that includes a :biff.graph/trace key, showing exactly where in the graph traversal the error occurred. Testing resolvers is straightforward — they're stored under :biff.graph/resolve-fn and take a single context map with input under :biff.graph/input.
Source: GitHub
Discussion
0 Comments
Be the first to start the discussion.