# Elide: a model-driven GraphQL and JSON-API layer for Java

> Elide is a Java library that turns annotated JPA entities into a GraphQL or JSON-API service, with permissions declared as annotations on the same classes, lifecycle hooks for business logic, and a separate analytic layer for aggregates. It is published by Yahoo, runs on Spring, Quarkus or standalone Jetty, and its whole pitch is that the API shape follows the model.

**yahoo/elide** — Elide is a Java library that lets you stand up a GraphQL/JSON-API web service with minimal effort.

- Repository: https://github.com/yahoo/elide
- Website: https://elide.io
- Stars: 1,032 · Forks: 240
- Language: Java
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/yahoo-elide

## The model is the API, and that is the whole idea

Elide is a Java library that lets you set up a model driven GraphQL or JSON API web service with minimal effort, and the README's tagline is Opinionated APIs for web and mobile applications.

The mechanism is that your existing JPA entities are the API. The simplest way to use Elide is by leveraging JPA to map your Elide models to persistence, and the models should represent the domain model of your web service. The example in the README is a Book entity with an id, a title and a many-to-many set of authors.

What makes this more than a generic JPA-to-JSON mapper is the annotation layer. You add Elide annotations to both expose your models through the web service and define security policies for access, on the same class:

```java
@Entity
@Include(rootLevel = true)
@ReadPermission("Everyone")
@CreatePermission("Admin OR Publisher")
@DeletePermission("None")
@UpdatePermission("None")
public class Book {

    @Id
    private Integer id;

    @UpdatePermission("Admin OR Publisher")
    private String title;

    @ManyToMany(mappedBy = "books")
    private Set<Author> authors;
}
```

Notice that the permissions exist at two levels. Class-level annotations govern the entity, and a field-level annotation on the title overrides it, so the title can be updated by an Admin or a Publisher even though the entity's update permission is None. That granularity is the feature: access control is a property of the model rather than something reimplemented in every handler.

The licence situation needs flagging. No licence is stated in the visible README text, and the repository listing includes a LICENSE.txt whose terms the reader has to consult directly. The repository metadata also records the licence as one GitHub cannot classify, so anyone planning to depend on it should read that file rather than infer a licence from the fact that it is published by Yahoo.

## Two API shapes, and a mutation model that is not CRUD

Elide supports two variants of API. A CRUD API for reading and manipulating models, and an analytic API for aggregating measures over zero or more model attributes.

The CRUD side is where the opinionated part lives, and the README lists the specific opinions. Create a new object and add it to an existing collection in the same operation. Create a set of related, composite objects, a subgraph, and connect it to an existing, persisted graph. Differentiate between deleting an object versus disassociating an object from a relationship without deleting it. Change the composition of a relationship to something different. And reference a newly created object inside other mutation operations.

That list is the difference between a generic API and a designed one. A REST controller that exposes a book and an author will have to invent semantics for the case where the client creates a book and assigns an existing author in one call, and where the client removes a relationship without deleting the author. Elide takes a position on those cases, and the position is in the data model rather than in your code.

Filtering, sorting, pagination and text search are supported out of the box, and the mobile-friendly claim rests on the same foundation. JSON-API and GraphQL let developers fetch entire object graphs in a single round trip, and only requested elements of the data model are returned. For a client on a poor network, that difference is the whole argument.

Atomicity for complex writes is the other structural property. Elide supports multiple data model mutations in a single request in either JSON-API or GraphQL, so you can create objects, add them to relationships, and modify or delete them together in a single atomic request.

Then there are the analytic queries, which run against models crafted with what the README calls its powerful semantic layer. Elide APIs work natively with Yavin, Yahoo's own visualisation and reporting tool, to visualise, explore and report on the data. So the project is not a GraphQL wrapper around tables, it has a second, deliberately different modelling layer for aggregates, with a semantic model of tables, measures, dimensions and joins, and a dedicated client in the same organisation.

## Analytic models, hooks, and where the customisation lives

The analytic layer has its own modelling language, and the README shows it as HJSON configuration.

```hjson
{
  tables: [
    {
      name: Orders
      table: order_details
      measures: [
        {
          name: orderTotal
          type: DECIMAL
          definition: 'SUM({{$order_total}})'
        }
      ]
      dimensions: [
        {
          name: orderId
          type: TEXT
          definition: '{{$order_id}}'
        }
      ]
    }
  ]
}
```

A table maps to a physical table, a measure is an aggregate with a definition, and a dimension is an attribute. Analytic models can be created either as POJOs or with this HJSON configuration language, and the definitions use a template syntax that references the underlying columns.

The other customisation points are computed attributes, data validation annotations and request lifecycle hooks, and the hook mechanism is the one that carries business logic. You add lifecycle hooks to your models to embed custom business logic that executes inline with CRUD operations through the web service:

```java
@LifeCycleHookBinding(operation = UPDATE, hook = BookCreationHook.class, phase = PRECOMMIT)
public class Book {
    // ...
}

public class BookCreationHook implements LifeCycleHook<Book> {
    @Override
    public void execute(LifeCycleHookBinding.Operation operation,
                        LifeCycleHookBinding.TransactionPhase phase,
                        Book book,
                        RequestScope requestScope,
                        Optional<ChangeSpec> changes) {
       //Do something
    }
}
```

The binding is by operation and phase, so a hook runs at a defined point in a transaction, and the changes parameter carries the pending change set. That is a proper extension point rather than a servlet filter, and it is the mechanism to reach for when the default semantics are not enough.

Custom security functions are the third piece. You map expressions to security functions or predicates that get pushed to the persistence layer:

```java
@SecurityCheck("Admin")
public static class IsAdminUser extends UserCheck {
    @Override
    public boolean ok(User user) {
        return isUserInRole(user, UserRole.admin);
    }
}
```

The phrase pushed to the persistence layer is the important one. A permission expression that is evaluated in the database rather than in memory is a permission that can use the indexes you already have, and that does not drag the whole table into memory to filter it. The @SecurityCheck annotation names the expression, and the class implements the predicate the expression resolves to.

## Storage, runtimes, and the shape of the build

Elide is agnostic to your particular persistence strategy, and you can use an ORM or provide your own implementation of a data store. The elide-datastore/ module is where that abstraction lives, and the elide-core/ module holds the model and annotation machinery, with elide-graphql/ for the GraphQL layer, elide-swagger/ for the generated schema documentation, elide-async/ and elide-model-config/ for their respective jobs, and elide-test/ for test support.

The runtime choices are visible in the module names, and there are three of them. elide-spring/ is the Spring integration, elide-quarkus/ is the Quarkus integration, and elide-standalone/ is the embedded option. The README points at the elide-standalone-example project, which allows you to quickly set up a local instance of Elide running inside an embedded Jetty application, and the elide-spring-boot-example for a fuller service.

That third runtime is the one to know about if you are evaluating. It gives you a working Elide instance with a real datastore and no application server to configure, which is the fastest possible answer to the question of whether Elide fits your domain model at all. A Spring or Quarkus integration is a decision about your application's architecture, and making that decision before you know whether the model-driven approach works for you is the wrong order.

The build is Maven, with a pom.xml at the root, an elide-bom/ module for the bill of materials, and an elide-integration-tests/ module. The coverage badge points at Coveralls, and there is a Screwdriver build badge alongside a Discord badge. The repository carries a checkstyle-style.xml, an elide-eclipse.importorder file and a sonar-project.properties, so the code style and static analysis configuration are part of the repository, which matters for a project whose contributors are expected to follow it.

The documentation points at versioned guide paths, with links to elide.io/pages/guide/v7/, and it is split into a JSON-API section and a GraphQL section, with separate pages for the start guide and for analytics. That version pinning in the URLs is a reminder to match your guide to your library version.

## Where Elide is the wrong choice

There are three limits, and they are structural rather than fixable.

The first is that the whole design assumes your domain is a relational model with stable entities and relationships. A model-driven API generator that derives the schema from JPA annotations can only expose what the annotations describe, so a domain that is really a graph of ephemeral documents, or a stream of events, does not fit the shape of the tool. The same applies to a domain with a very large number of similar types, where a hand-written GraphQL schema is more work than the generator saves.

The second is that opinionated means some things you cannot have. Elide gives you CRUD plus analytics and it gives you a specific set of mutation semantics, and if your API consumers need something outside that set, you are extending the framework rather than using it. The README is upfront about the model-driven approach and the opinionated mutation behaviour, and that honesty is a virtue, but it is also a limit on the API surface your clients see.

The third is the version churn. The releases come a few months apart, 7.2.0 in August 2026, 7.1.17 in April, 7.1.16 in January, and the documentation lives under versioned paths that you have to match to your dependency. A framework that publishes a new 7.x release every few months is pleasant to work with and unpleasant to pin, and the interaction with a Spring Boot application's own dependency management is where that shows up.

The alternative for comparison is not another model-driven generator, it is the two ends of the spectrum. The first is hand-written GraphQL with a schema-first tool, which gives you total control over the API shape and no reflection or annotation magic, at the cost of writing and maintaining the schema and the resolvers. The second is a plain REST API over JPA, which many teams already have, and which Elide replaces when the round-trip fetching and the multi-mutation atomicity become a real requirement. The deciding question is whether your clients need to traverse and mutate the object graph in one request, because that is the case Elide is built for and the case a hand-written REST layer is built against.

## Conclusion

Adopt Elide if you have JPA entities and want a GraphQL or JSON-API over them in days rather than months, and you are prepared to express access control as annotations on the model. Do not adopt it if your domain does not map cleanly to a relational model, since the library is model-driven, or if you need a REST API with hand-written resource semantics, since Elide deliberately does not provide that. Verify first that the version you use matches the guide you follow, because the documentation paths carry a v7 prefix, and that the runtime you pick, Spring, Quarkus or standalone, matches the module you depend on.

## FAQ

### What is Elide and what does it generate?

Elide is a Java library that sets up a model driven GraphQL or JSON API web service with minimal effort from JPA-annotated entities. It supports a CRUD API for reading and manipulating models and an analytic API for aggregating measures over model attributes.

### How does Elide handle access control?

Through declarative annotations on the model, with permissions defined per class and overridable per field, such as @ReadPermission("Everyone") and @UpdatePermission("Admin OR Publisher"). Custom expressions are mapped to security functions or predicates with @SecurityCheck, and the README states these are pushed to the persistence layer.

### Which runtimes does Elide support?

The repository contains elide-spring for Spring, elide-quarkus for Quarkus, and elide-standalone for an embedded option, with the elide-standalone-example project described as a way to quickly set up a local instance running inside an embedded Jetty application.

### What licence is Elide released under?

The licence recorded in the repository metadata as one GitHub cannot classify, with a LICENSE.txt in the repository listing, and the visible README text does not reproduce the terms, so the file has to be consulted directly rather than inferred.

## Sources

- [Issues](https://github.com/yahoo/elide/issues)
- [Project website](https://elide.io)
- [README](https://github.com/yahoo/elide/blob/master/README.md)
- [Releases](https://github.com/yahoo/elide/releases)
- [yahoo/elide on GitHub](https://github.com/yahoo/elide)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yahoo-elide
