
Dreamforce 2026: What AIforce Changes for Enterprise AI ArchitectureRead More

Audience: developers who want to use deep learning models without rewriting their stack.
Goal: understand what DJL is, where it fits, and how to get productive quickly—whether you write only Java, only Python, or both.
Deep Java Library (DJL) is an open-source, engine-agnostic deep learning library for Java. It lets you run and serve modern AI models from the JVM (inference and training) while staying in your Java tooling (Maven/Gradle, Spring Boot, observability, deployment pipelines). DJL isn’t “Java trying to replace Python”—it’s a pragmatic bridge: train or fine-tune in Python if you want, then ship inference in Java cleanly, safely, and at scale.
DJL (Deep Java Library) is a set of Java APIs and runtime components that make it straightforward to:
Instead, DJL is a JVM-friendly façade over proven engines (e.g., PyTorch, TensorFlow, ONNX Runtime, MXNet—availability varies by platform and DJL version). The key value: you interact with a consistent Java API while choosing the engine that matches your model and deployment constraints.
Most production systems aren’t “all Python.” They’re:
Python is phenomenal for research and iteration, but many teams still want:
DJL is one of the most direct ways to run modern ML models inside that world.
You don’t need to memorize everything, but it helps to know the “shape” of DJL.
An engine is what actually executes tensor operations. DJL hides engine differences behind a stable Java API.
Practical Implications:
DJL provides its own tensor abstraction (NDArray) and a memory lifecycle helper (NDManager).
If You’ve Used Python Libraries:
A Practical Rule: treat NDManager like a scoped resource manager. Create arrays inside a scope; close the manager when you’re done.
In DJL you typically:
DJL’s model zoo concept helps you start fast:
This is great for learning, demos, and bootstrapping.
If you build anything non-trivial with DJL, you’ll see Criteria. Think of it as the manifest of what you want:
Why this matters: it forces you to be explicit about assumptions. In production, implicit assumptions are what turn into 3 AM incidents.
Most inference bugs aren’t “the model is wrong”—they’re:
In Python, you often hide these details in a preprocessing pipeline. In DJL, the Translator is the explicit, testable place for them.
Practical habit: treat the translator like production code. Give it unit tests and golden vectors.
DJL represents compute targets as Device instances. Even if you start on CPU, design with a “device is configurable” mindset.
Typical Pattern:
This is how you avoid hard-coding yourself into a corner.
DJL can do both training and inference, but most teams get value fastest by focusing on inference first.
When inference-first is the right call:
When Java-side training makes sense:
Engine selection is where many beginners get stuck. Here’s a simple decision guide:
The key: don’t pick an engine by ideology. Pick it by “what model artifact do I have and what platform do I deploy on?”
DJL is the most “natural” if your primary language is Java.
You don’t need to become a deep learning researcher. You can treat models like a dependency:
Even if you never write Java, DJL can still be relevant.
This can reduce operational friction: the team that owns the Java platform can deploy and monitor the model without needing a full Python runtime in the service.
Hybrid teams get the best of both worlds.
This reduces “translation loss” between research and production.
DJL’s API is separate from engine dependencies. You typically include:
Example (you will adjust versions to your target):
<dependencies>
<dependency>
<groupId>ai.djl</groupId>
<artifactId>api</artifactId>
<version>0.30.0</version>
</dependency>
<!-- Choose ONE engine (example: PyTorch engine) -->
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-engine</artifactId>
<version>0.30.0</version>
</dependency>
<!-- Optional: a basic logger implementation -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.13</version>
</dependency>
</dependencies>Notes:
A common DJL inference flow in Java looks like:
Pseudo-structure:
Criteria<InputType, OutputType> criteria = Criteria.builder()
.setTypes(InputType.class, OutputType.class)
.optModelUrls("...")
.optTranslator(new MyTranslator())
.build();
try (ZooModel<InputType, OutputType> model = criteria.loadModel();
Predictor<InputType, OutputType> predictor = model.newPredictor()) {
OutputType out = predictor.predict(input);
// handle output
}Don’t worry if this looks “frameworky”—it’s mostly about making model loading and preprocessing explicit.
It’s much easier to learn DJL with a real example you can run. The pattern below is intentionally “boring Java”—no magic, no reflection-heavy frameworks.
What this example does
In addition to ai.djl:api, you typically add:
Example (Maven):
<dependencies>
<dependency>
<groupId>ai.djl</groupId>
<artifactId>api</artifactId>
<version>0.30.0</version>
</dependency>
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-engine</artifactId>
<version>0.30.0</version>
</dependency>
<!-- Enables convenient access to pretrained PyTorch models via the DJL model zoo. -->
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-model-zoo</artifactId>
<version>0.30.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.13</version>
</dependency>
</dependencies>
If you pick a different engine (for example ONNX Runtime), you’ll choose the corresponding engine + model-loading approach.
5.4.2 Java code (single-file demo)
import ai.djl.Application;
import ai.djl.ModelException;
import ai.djl.inference.Predictor;
import ai.djl.modality.Classifications;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ZooModel;
import ai.djl.translate.TranslateException;
import java.io.IOException;
import java.nio.file.Path;
public class ImageClassificationDemo {
public static void main(String[] args) throws IOException, ModelException, TranslateException {
if (args.length != 1) {
System.err.println("Usage: java ImageClassificationDemo <path-to-image>");
System.exit(2);
}
Path imagePath = Path.of(args[0]);
Image img = ImageFactory.getInstance().fromFile(imagePath);
Criteria<Image, Classifications> criteria = Criteria.builder()
.optApplication(Application.CV.IMAGE_CLASSIFICATION)
.setTypes(Image.class, Classifications.class)
// You can add filters to select a specific architecture.
// Filters depend on the model zoo and engine.
.optFilter("layers", "50")
.build();
try (ZooModel<Image, Classifications> model = criteria.loadModel();
Predictor<Image, Classifications> predictor = model.newPredictor()) {
Classifications result = predictor.predict(img);
System.out.println(result.topK(5));
}
}
}What to learn from this code
Embeddings are one of the most common “I want AI in my Java app” use cases:
In Python, you might use sentence-transformers. In Java, the goal is the same: turn text into a vector and store it in a vector DB (or even just compute cosine similarity).
Conceptual Pipeline:
DJL can do this, but the details depend on the exact model and tokenizer. The “lesson” is: treat preprocessing and pooling as part of the model contract.
A common question is: “Can I keep a Predictor in a singleton and call it from multiple requests?”
The safe default is:
Simple approach for web APIs:
For real systems, do not stop at “it runs.” Add tests that lock down correctness:
When you export from Python, include those golden vectors in the handoff package. This is how you prevent silent regressions when:
Notebook magics are great for learning, but production should use pinned versions.
Tips:
This is a great way to learn DJL because you can execute Java incrementally—like a Python notebook.
You already installed these in this workspace:
From the workspace venv:
/Users/adeel.aslam/projects/djl/.venv/bin/jupyter kernelspec listYou should see a java kernel.
The “Dive into Deep Learning (DJL)” notebooks often use a magic like:
%maven ai.djl:api:...
%maven ai.djl.mxnet:mxnet-engine:...That’s a notebook convenience: dependencies are fetched during the session.
For production code, you generally don’t do this—you pin dependencies in Maven/Gradle.
When you’re learning, you want a tiny feedback loop.
Start with a cell like:
System.out.println("Java kernel is alive");If that prints, you’ve verified:
In the D2L DJL notebooks, you’ll commonly see dependency cells. The idea is:
Example:
// DJL API
%maven ai.djl:api:0.20.0
// Logging
%maven org.slf4j:slf4j-simple:2.0.1Then pick an engine. For example, a notebook might choose MXNet or PyTorch depending on the chapter.
Notebook magics are convenient, but they hide production concerns:
If your end goal is a production service, do both:
Before you invest hours in a chapter, run a quick “can I allocate a tensor?” check:
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDManager;
try (NDManager manager = NDManager.newBaseManager()) {
NDArray a = manager.create(new float[]{1, 2, 3});
System.out.println(a);
}If that works, you’re past the most common environment issues.
DJL is Java-first, but Python users can still benefit from DJL in a few practical ways.
If you’re training in Python, the cleanest bridge is to export your model to a standard format and ship that to the Java team.
Common Export Choices:
A “handoff package” that works well in real teams:
The Java team then uses DJL to load and run it.
This is the most repeatable workflow I’ve seen across teams.
The exact code depends on your model, but the pattern is consistent:
Example (PyTorch → ONNX):
import torch
model.eval()
dummy = torch.randn(1, 3, 224, 224) # example shape for a CV model
torch.onnx.export(
model,
dummy,
"model.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch"}, "output": {0: "batch"}},
opset_version=17,
)Golden vectors are your insurance policy.
For classification:
For embeddings:
Write them down in a small JSON file so Java can run the same checks.
For many models, preprocessing is half the model.
Document:
If Java does preprocessing differently than Python did, you will get different answers even if the model weights are identical.
On the Java side you:
At a high level:
import ai.djl.Model;
import ai.djl.inference.Predictor;
import ai.djl.ndarray.NDList;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ZooModel;
import java.nio.file.Path;
Criteria<NDList, NDList> criteria = Criteria.builder()
.setTypes(NDList.class, NDList.class)
.optModelPath(Path.of("model.onnx"))
// optEngine("OnnxRuntime") // optional, depending on setup
.build();
try (ZooModel<NDList, NDList> model = criteria.loadModel();
Predictor<NDList, NDList> predictor = model.newPredictor()) {
NDList output = predictor.predict(input);
}This example uses NDList to keep things generic. In real code, you wrap this behind a typed API so the rest of your service doesn’t speak “tensors.”
Run golden-vector checks in Java CI.
If you can, run the same checks in Python CI. When results diverge, you’ll know whether it’s preprocessing, export, runtime, or model drift.
For NLP models, tokenization is a common source of mismatch.
If the model was trained with a specific tokenizer implementation/version, treat it as part of the artifact. Don’t “reimplement it by hand” unless you’re willing to validate the behavior thoroughly.
ONNX is a great default, but it isn’t universal.
Avoid ONNX as the bridge if:
In those cases, use TorchScript or a serving boundary (Python service) and revisit later.
Many teams adopt DJL not just for “inference in a main method,” but for serving.
Pros:
Cons:
Pros:
Cons:
DJL Serving is a production-oriented model server built around DJL.
Typical reasons teams prefer it:
(If you want, we can set this up after you’re comfortable running basic inference.)
The engine and native libraries determine how GPU support works.
Deep learning libraries often allocate memory outside the Java heap.
Practical advice:
A major advantage of “AI inside the JVM” is using standard tooling:
This is often a deciding factor for platform teams.
If you want a post that resonates with engineering leaders and Java devs:
Here’s a short snippet you can adapt:
We didn’t switch our stack to ship AI. We brought AI to our stack.
Deep Java Library (DJL) lets JVM teams run modern deep learning models with Java-first ergonomics—Maven dependencies, typed APIs, and production observability.
Python stays great for research and training, but DJL makes inference and serving feel like a normal part of a Java service.
You’re installed and ready.
If you want the most confidence quickly, the next best check is:
If you tell me which chapter notebook you want to start with (or I can pick a small one), I can automate a full “run-all-cells” smoke test and fix any dependency/engine issues you hit on macOS (Apple Silicon).
This section is intentionally practical. If you’re stuck, it’s usually one of these.
Symptom: you run int x = 21; and Jupyter complains like it’s Python.
Cause: the notebook is using the Python kernel.
Fix:
jupyter kernelspec listYou should see a java kernelspec.
Common causes:
Quick check:
java --list-modules | grep "jdk.jshell"If you don’t see jdk.jshell@..., fix your Java installation/path.
This is often due to implicit downloads.
What happens:
Fix patterns:
In order of likelihood:
Fix:
Deep learning engines rely on native code. Errors often look like:
Fix:
DJL is a great tool, but the best architecture depends on your constraints.
Best when:
Trade-offs:
Best when:
Trade-offs:
Best when:
Trade-offs:
Sometimes teams do this for speed of integration, but it’s rarely the best long-term option.
Trade-offs:
Rule of thumb: if the model is going to live for months/years in production, invest in a clean boundary (DJL embedded, DJL Serving, or a dedicated service).
If you want DJL to go smoothly in a real organization, align on these:
Artifact format
Preprocessing contract
Golden vectors
Version pinning
Performance plan
Operational plan
If you do just one thing from this list: do golden vectors. They pay for themselves.
Trusted by top platforms for our transformative solutions and exceptional results:






