# Deep Java Library (DJL): engine-agnostic deep learning for Java teams

> DJL is an Apache-2.0 Java framework that lets you load, train and serve models without committing to a single deep learning engine. It suits Java developers who want inference inside an existing JVM service, not researchers chasing the newest architectures on day one.

**deepjavalibrary/djl** — An Engine-Agnostic Deep Learning Framework in Java

- Repository: https://github.com/deepjavalibrary/djl
- Website: https://djl.ai
- Stars: 4,854 · Forks: 759
- Language: Java
- License: Apache-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/deepjavalibrary-djl

## The JVM gap DJL is trying to close

Most production Java services already run on the JVM: Spring services, Spark jobs, Android apps, batch pipelines. The deep learning ecosystem, meanwhile, is Python-first. The usual workaround is a Python sidecar or a REST service that the Java application calls over the network. That adds a second runtime, a second deployment artifact and a serialization boundary on every prediction.

DJL takes the opposite position. The README describes it as an "open-source, high-level, engine-agnostic Java framework for deep learning" that is "designed to be easy to get started with and simple to use for Java developers". The stated goal is that you use your existing Java expertise as the on-ramp, and that you can build, train and deploy inside your favorite IDE.

The audience is therefore narrow and specific: backend and platform engineers who need a model inside a JVM process, not data scientists choosing an architecture. If your team writes Python and deploys models as services, DJL solves a problem you do not have.

## How engine agnosticism actually works

The mechanism that makes DJL different is the split between the API and the engine. The repository layout shows this directly: there is an api/ module, a separate engines/ directory, and a model-zoo/ directory. The api module defines the interfaces, and each engine directory provides an implementation of them. The README states that because DJL is engine agnostic "you don't have to make a choice between engines when creating your projects. You can switch engines at any point."

The topics list names the engines the project associates with itself: PyTorch, TensorFlow, MXNet and ONNX Runtime. The README also says DJL "provides automatic CPU/GPU choice based on hardware configuration", so the same code can run on a machine without a GPU and on one with a GPU, with the engine selection handled at load time rather than compile time.

The second layer is the model zoo. In the inference example, a Criteria builder collects the application type, the input and output types, and a filter on a model property such as the network backbone. The model itself is then resolved from the zoo rather than from a local file path. That is a real convenience, but it also means the zoo is a dependency: if your architecture or task is not represented there, you fall back to loading your own model artifact.

On the training side the abstraction is a Block, which is the neural network definition, attached to a Model, then handed to a Trainer with a TrainingConfig. The README's training example builds an Mlp block, attaches it, initializes the trainer with an input Shape, fits it with EasyTrain.fit, and saves the result with model.save(modelDir, "mlp").

## Installing DJL and running your first inference

DJL is published to Maven, and the repository ships a working examples project (examples/pom.xml and examples/build.gradle.kts) that is the most reliable place to copy a build definition from. The dependency coordinates are the api artifact plus one engine artifact; the README does not list the coordinates itself, so take them from the examples project or the Maven repository rather than guessing. A Gradle build for a PyTorch-backed project takes this shape:

```bash
git clone https://github.com/deepjavalibrary/djl.git
cd djl/examples
./gradlew run
```

The examples project is a multi-module build, so a bare run without a module argument will not do what you want. Point it at a specific example module instead, or open the project in your IDE and run a main class from there.

The core inference code follows the pattern the README gives. You describe what you want, and the zoo resolves a model:

```java
Criteria<Image, Classifications> criteria =
        Criteria.builder()
                .optApplication(Application.CV.OBJECT_DETECTION)
                .setTypes(Image.class, Classifications.class)
                .optFilter("backbone", "resnet50")
                .build();
```

Then you load the model, create a predictor, and predict. Both are closeable resources, and the README wraps them in try-with-resources, which is worth copying because the native engine holds memory outside the Java heap:

```java
Image img = ImageFactory.getInstance().fromUrl("http://...");
try (ZooModel<Image, Classifications> model = criteria.loadModel();
     Predictor<Image, Classifications> predictor = model.newPredictor()) {
    Classifications result = predictor.predict(img);
}
```

What you should see is a Classifications object containing labels and probabilities. The first run downloads the model and the native engine library, so it is slower than subsequent runs and needs network access. If you are behind a proxy or in an air-gapped environment, that download step is the first thing that will fail, and the README does not document an offline mirror workflow.

## Training in Java, and where the abstraction leaks

Training is supported, and the README's example is honest about what it involves. You construct a Block, create an empty Model with Model.newInstance, set the block, build datasets, define a TrainingConfig with initializer, optimizer and loss, create a Trainer, call trainer.initialize with an input Shape, run EasyTrain.fit, and save.

The initialization step is the part that trips people up. The README's own comment explains why: the first axis is the batch axis, and you use 1 for initialization. So a 28x28 grayscale MNIST input is declared as new Shape(1, 28 * 28). If your declared shape does not match what the dataset actually yields, you get a failure at the first forward pass rather than at the point where you wrote the shape. That is a design trade-off: the framework cannot infer the shape from the data without consuming it.

EasyTrain.fit is the convenience layer. It handles the epoch loop, but anything beyond a standard supervised loop (custom metrics, gradient manipulation, unusual batching) means dropping to the lower-level Trainer API. The README does not document that lower-level path. My read is that DJL's training side is aimed at fine-tuning and small-to-medium models, while the inference side is the more mature half of the project. The README's own framing supports that: the first example it shows is inference from a pre-trained model, and the training example is a textbook MNIST MLP.

## DJL Serving and the deployment story

The repository contains a serving/ directory, and search data shows people look for "djl-serving" and "deep java library/djl-serving" specifically. That is a separate deployment component rather than part of the core library, and it is the route to take if you want a model server rather than an embedded library. The README does not describe its configuration, so treat the serving directory and the documentation site as the starting point rather than this article.

The distinction matters for architecture. Embedding DJL means your Java process owns the model, the native engine and the memory. Running DJL Serving means a separate process owns them and your application talks to it. The first gives you lower latency and no extra hop; the second gives you independent scaling and lets several services share one loaded model. The repository also includes a docker/ directory and an android/ directory, which indicates the project intends to support both containerized and on-device deployment, though the README documents neither.

## Alternatives and the real difference in approach

The obvious alternative for JVM teams is ONNX Runtime directly. ONNX Runtime is itself one of the engines DJL lists, so the comparison is not adversarial: DJL can use it underneath. The difference is the layer you program against. With ONNX Runtime directly you manage sessions, input tensors and output tensors yourself, and you get a stable, narrow interface with no model zoo and no training API. With DJL you get a higher-level abstraction, model resolution by criteria, image and NDArray types, and the option to train. The cost is an extra abstraction layer and a dependency on DJL's release cadence for engine updates.

The other alternative is to keep the model in Python and expose it over HTTP. That is the right call when the model changes weekly, when it uses an architecture that has no Java-side implementation, or when the team maintaining it writes Python. DJL does not remove the need for Python in those cases; it removes the need for a second runtime in the cases where it does not apply.

## Maintenance, releases and the Apache-2.0 licence

The last push to the default branch was on 2026-09-10, and the most recent releases are v0.38.0 on 2026-09-09 and v0.37.0 on 2026-09-08, with v0.36.0 before that on 2025-12-16. The gap between v0.36.0 and v0.37.0 is roughly nine months, and then two releases land on consecutive days. That pattern suggests batched work rather than a steady drip, which matters if you need a specific engine bug fixed on a deadline. The versioning is still 0.x, so minor releases can carry breaking changes; the README's release notes list jumps such as 0.33.0 and 0.32.0 without describing migration steps.

The licence is Apache-2.0, which permits commercial and closed-source use and includes a patent grant. The repository also carries a NOTICE file, which Apache-2.0 requires you to propagate in distributions. DJL bundles or downloads native engine binaries, and those come under their own upstream licences, not Apache-2.0. That is the part to check against your own distribution policy: DJL's licence covers DJL's code, not the engine it loads at runtime.

## Conclusion

Adopt DJL if your team already ships JVM services and wants inference or light training without leaving Java, or if you need to swap between engines such as PyTorch, TensorFlow, MXNet and ONNX Runtime through one API. Do not adopt it as a research framework, and do not expect the training-side documentation to be as deep as the inference-side. Before committing, verify that a model for your task exists in the model zoo or can be loaded from your own artifact, that the engine you intend to use is available for your platform, and that your build resolves the api, engine and model-zoo artifacts at the version you pin.

## FAQ

### What can Deep Java Library (DJL) be used for?

The README shows two uses: running inference with a pre-trained model from the model zoo, and training a network in Java with Block, Trainer and EasyTrain.fit. The repository also contains a serving component and an Android directory.

### What are the top 10 Java libraries?

The README does not rank Java libraries. It does describe Deep Java Library as an open-source, engine-agnostic Java framework for deep learning, licensed under Apache-2.0, with modules for an API, engines and a model zoo.

### What is DJL AI?

DJL is the Deep Java Library, described in the README as an open-source, high-level, engine-agnostic Java framework for deep learning. It is licensed under Apache-2.0 and hosted by the deepjavalibrary organization on GitHub.

### How can I use deep learning in Java with DJL?

Add the DJL api artifact and one engine artifact to your build, then use a Criteria builder to select a model, load it with criteria.loadModel() and predict through a Predictor. The README wraps both in try-with-resources because they hold native resources.

## Sources

- [deepjavalibrary/djl on GitHub](https://github.com/deepjavalibrary/djl)
- [License: Apache-2.0](https://github.com/deepjavalibrary/djl/blob/master/LICENSE)
- [Project website](https://djl.ai)
- [README](https://github.com/deepjavalibrary/djl/blob/master/README.md)
- [Releases](https://github.com/deepjavalibrary/djl/releases)

---

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