Library / SDK
deepjavalibrary/djl-demo avatar
deepjavalibrary/djl-demo

djl-demo: a reference shelf of DJL examples, not a library you install

Demo applications showcasing DJL

352 stars139 forksJupyter NotebookApache-2.0

At a glance

What is it?
The deepjavalibrary/djl-demo repository collects runnable examples for Deep Java Library, an engine-agnostic Java API for deep learning. Its value is breadth of integration patterns, and its cost is that every directory carries its own dependencies and setup.
Who is it for?
Adopt djl-demo as a source of working reference code when you already run DJL in Java and need a concrete pattern for one integration: Android with a PyTorch model, Spark image classification, a Quarkus or Camel service, or a Lambda endpoint. Do not adopt it as a dependency, a starter template, or a place to look for a maintained API surface, because the repository is a collection of independent example directories rather than a released artifact.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 158 days ago.
What is it written in?
Mainly Jupyter Notebook, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap djl-demo fills is integration, not model code

DJL itself is described in this repository's README as a framework-agnostic Java API for deep learning. That phrase hides the hard part. Getting a model to load in Java is one problem; getting it to load inside a Quarkus service, an Android activity, an Apache Flink job, or an AWS Lambda handler is a different problem each time. djl-demo exists to answer those second-order questions with code you can read.

The audience is narrow and specific. You need to be writing Java, and you need to have already decided that DJL is the API you want between your application and whatever engine actually executes the tensors. If you are choosing a runtime from scratch, this repository will not help you choose. It assumes the choice.

The breadth is the point. Inference examples cover a malicious URL detector built on a character-level CNN, pneumonia detection from X-ray images using a trained Keras model through the TensorFlow engine, live object detection from a web camera, and a browser-based doodle game. Training examples cover footwear classification and a Vue front end that visualises loss and accuracy during a run. Those are not toy shapes; each one picks a different input pipeline and a different output surface.

How the examples are laid out and what each one actually wires together

The repository is organised by deployment target first and task second. Top-level directories split into inference, training, Android, AWS services, big data integration, and a catch-all for development experiments. That ordering is deliberate: it tells you the maintainers expect you to arrive with a platform question, not a model question.

The Android tree is the clearest illustration. Every example there targets PyTorch, and each one pairs a model with a device capability: face detection, quickdraw recognition, CycleGAN style transfer, semantic segmentation, French to English neural machine translation, and speech recognition. One example sits outside that pattern, object detection with an ONNX model under android/onnxruntime_android, which shows the same Android shell driving a different engine. That single outlier is more informative than the rest of the directory, because it demonstrates that the engine boundary in DJL is real and swappable at the application level.

The big data directory makes the same point in the opposite direction. Spark image classification, Apache Beam click-through-rate prediction, and Apache Flink sentiment analysis each embed inference inside a distributed execution model where the per-record cost of model invocation matters. A Camel example and a Quarkus example then show the HTTP service shape.

Two development examples are worth calling out because they document constraints rather than tasks. The multi-engine example runs several deep learning frameworks inside one JVM, and the GraalVM example compiles DJL applications into native executables. Those two are where you learn what the runtime will and will not tolerate.

Getting one example running means reading its own README first

There is no repository-level build command that brings everything up, and the README does not offer one. Each entry in the list links to a subdirectory README, for example development/python/README.md, malicious-url-detector/README.md, or aws/lambda-model-serving/README.md. Those files are where the actual build and run instructions live.

This is the single most important operational fact about the repository. The top-level README is an index with one-line descriptions. Treat it as a table of contents and nothing more. If you clone the repository and look for a root pom.xml or build.gradle that compiles every module, you are looking for something the supplied material does not describe.

The one piece of automation visible in the material is the nightly workflow, referenced by the badge at the top of the README and located at .github/workflows/nightly.yml. Its existence tells you the examples are exercised on a schedule rather than only at release time. It does not tell you which examples are covered, how long they take, or what a failure means, because the README does not say. That is a question you answer by opening the workflow file.

Practical consequence: budget your time per example, not per repository. Pick the one directory that matches your platform, read its README in full, and expect to resolve its specific model and engine dependencies before anything runs.

The notebook-heavy layout is a real friction point

The primary language listed for this repository is Jupyter Notebook, and that is not incidental. Several examples are presented as notebooks, which is a reasonable choice for training walkthroughs where you want to see intermediate output, and a poor choice when what you actually need is a build file you can drop into an existing service.

If your goal is a production service, you will spend time translating notebook cells into a Maven or Gradle module. That translation is not mechanical. Notebooks tend to inline configuration that a service would externalise, and they tend to assume a single execution order that a service does not have.

The Android and AWS directories are the exception and are closer to what a service developer wants, since they are described as example applications rather than notebooks. If you are evaluating whether DJL fits a server-side or mobile deployment, start there rather than in the training examples.

There is also a duplication in the README itself: the AWS Elastic Beanstalk model serving entry appears twice, with identical text and identical link. It is a cosmetic defect, but it is the kind of thing that signals the index is maintained by hand and drifts.

Where djl-demo is the wrong tool

This repository is not a stable API. Nothing in the supplied material indicates a release process for the demo code itself, and the recent releases field is empty. The default branch is master, and the last push recorded is 2026-04-11. If you vendor code from here into a service, you own it from that moment, including any engine version assumptions baked into the example.

It is also the wrong place to look if you have not committed to Java. The entire repository is built around a Java API. A Python-first team will find nothing here that transfers, and the one Python-adjacent example, development/python/README.md, is about calling Python pre- and post-processing from DJL, not about doing the modelling in Python.

A third case: if you need a supported, versioned distribution with a compatibility matrix, examples are the wrong artifact class. Examples demonstrate that something can work. They do not promise it will keep working across engine upgrades, and the nightly workflow is the only signal in the material that anyone is watching.

Finally, do not read the directory listing as a feature comparison. The presence of an Inferentia example does not mean DJL has first-class Inferentia support in the sense a vendor SDK does; it means someone wrote an example that runs inference on it.

The alternative is the engine's own Java bindings, and the difference is who owns the abstraction

The obvious alternative for a Java team is to skip DJL and use an engine's own Java or JNI bindings directly, for instance PyTorch's Java bindings, or ONNX Runtime's Java API. The difference is where the abstraction sits.

With engine-native bindings, your application code is written against that engine's types and lifecycle. You get the shortest path to that engine's newest features, and you get a hard dependency on that engine everywhere in your codebase. Switching engines later means rewriting the call sites, not changing a dependency.

With DJL, the engine is selected behind the API. The djl-demo repository is the evidence for this: the Android directory runs PyTorch models across six examples, and android/onnxruntime_android runs an ONNX model in the same application shape. That is the trade the project is making. You give up direct access to engine-specific APIs in exchange for the ability to change engines without rewriting the application.

If you know you will only ever run one engine and you want its full surface area, the native bindings are the more direct choice. If you are writing a service that may need to swap engines, or that needs to run multiple engines in one process, the multi-engine example under development/multi-engine is the concrete demonstration of why the abstraction exists.

Licence and upkeep

The repository is Apache-2.0. That is a permissive licence, and it is the same licence family DJL itself uses, which keeps the copying question simple at the repository level. It does not resolve the licence of the models the examples load. Several examples reference pretrained models, including a Keras model for pneumonia detection and PyTorch models for the Android demos, and those artifacts carry their own terms. Check the model source before shipping anything built on one. This is a description of what to look at, not legal advice.

Upkeep cost is per example, and it is dominated by engine and model versions rather than by the demo code. The nightly workflow is the mechanism that would surface breakage, so the practical maintenance question is whether the example you depend on appears in that workflow. If it does, you get a signal. If it does not, you are the only one who will notice when an engine upgrade changes behaviour.

Because the top-level README is a hand-maintained index and already contains a duplicated Beanstalk entry, treat the index as a starting point rather than a specification. The subdirectory README is the artifact that matters, and it is the thing to re-read after any engine upgrade.

Editorial conclusion

Adopt djl-demo as a source of working reference code when you already run DJL in Java and need a concrete pattern for one integration: Android with a PyTorch model, Spark image classification, a Quarkus or Camel service, or a Lambda endpoint. Do not adopt it as a dependency, a starter template, or a place to look for a maintained API surface, because the repository is a collection of independent example directories rather than a released artifact. Before copying anything, open the subdirectory README for the example you want and confirm which engine and model artifacts it expects, then check the nightly workflow at .github/workflows/nightly.yml to see whether that example is still exercised in CI.

Official sources

  1. deepjavalibrary/djl-demo on GitHub
  2. Issues
  3. License: Apache-2.0
  4. Project website
  5. README
Community notes

Community notes