Jittor: A JIT-Compiled Deep Learning Framework Where Every Op Is Generated at Runtime
Jittor is a high-performance deep learning framework based on JIT compiling and meta-operators.
At a glance
- What is it?
- Jittor compiles its entire operator set just-in-time from Python source down to CUDA or C++, and exposes a meta-operator layer so you can write new kernels without leaving Python. It is a research framework from Tsinghua, not a drop-in replacement for PyTorch, and the install path itself is the first thing to evaluate.
- Who is it for?
- Adopt Jittor if you are doing research that needs custom operators written in Python and compiled at runtime, and you are willing to run the manual install path with a chosen compiler (g++, clang++-8, or icc) plus an explicit nvcc_path. Do not adopt it if you need a stable ABI for shipping binaries, a large third-party package ecosystem, or a team that has never compiled anything.
- 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 received new commits within the last day.
- What is it written in?
- Mainly Python, 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 Problem Jittor Targets: Kernel Writing Without Leaving Python
Most frameworks ask you to choose between two things. You can write models in Python and accept whatever kernels the framework ships with, or you can write custom CUDA and accept that you are now maintaining C++ in a separate build system. Jittor's stated position is that the whole framework and its meta-operators are compiled just-in-time, and that a compiler plus tuner are integrated so the generated code is specialized for your model. The audience is the researcher who needs a convolution variant, a fused activation, or an unusual gradient, and does not want to drop into a separate CUDA toolchain to get it. The README points to a notebook titled Meta-operator: Implement your own convolution with Meta-operator, which tells you the intended workflow: define the operation in Python, let the JIT layer lower it. That is a narrower and more specific goal than general framework parity.
How the JIT and Meta-Operator Layer Actually Fit Together
The architecture described in the README is split cleanly. The front end is Python, using a Module design with dynamic graph execution, which the README calls the most popular design for deep learning framework interfaces. The back end is high performance language, specifically CUDA and C++. The bridge is the op compiler and tuner. When you define a model, the operators are not taken from a fixed precompiled library. They are compiled just-in-time, and the tuner selects among generated variants for your model's shapes. The meta-operator layer sits above that. A meta-operator is a Python-level description of an operation, and the compiler turns that description into runnable code. The payoff is specialization: the generated kernel matches the model rather than a generic shape. The cost is that compilation happens at runtime, so the first execution of a new shape is not free. The README does not publish compile-time numbers, and I have not measured them, so treat the first-call latency as something you must observe on your own workload rather than something you can look up.
What the Training Loop Looks Like in Practice
The README gives a complete two-layer network, and it is worth reading closely because it shows the framework's conventions. You subclass Module and implement execute, not forward. The example uses nn.Linear, nn.Relu, and nn.SGD, and the optimizer step takes the loss directly: optim.step(loss_mean). Data is yielded as jt.float32 tensors. The loss is computed with plain arithmetic, dy = pred_y - y, then loss = dy * dy, then loss.mean(). There is no autograd tape visible in user code. The README also shows printing loss_mean.data.sum(), which means .data is the escape hatch to the underlying value. Two things follow from this. First, the API is close enough to PyTorch that porting a small model is mechanical, but execute versus forward and step(loss) versus step() after backward() are real differences that will break copied code. Second, because the graph is dynamic and the ops compile just-in-time, a loop that changes tensor shapes every iteration is the worst case for this design.
Installing Jittor: Three Paths and the Environment Variables That Matter
The README offers pip, Docker, and manual installation. The pip path on Linux is sudo apt install python3.7-dev libomp-dev followed by python3.7 -m pip install jittor, then python3.7 -m jittor.test.test_example. On Windows the requirement is Python 3.8 or higher, python -m pip install jittor, and conda install pywin32 if you use conda. The manual path is the one that exposes how the framework is wired. You pick a back-end compiler first, either g++ via sudo apt install g++ build-essential libomp-dev, or clang++-8 via the install_llvm.sh script. Then you clone the repository, run sudo pip3.7 install ./jittor, and set export cc_path="clang++-8" (the README notes g++ and icc as alternatives). CUDA is enabled by setting export nvcc_path="/usr/local/cuda/bin/nvcc" and running python3.7 -m jittor.test.test_cuda. At runtime, jt.flags.use_cuda = 1 turns it on. On Windows, jittor will automatically detect and install CUDA, or you can run python -m jittor_utils.install_cuda, provided your NVIDIA driver supports CUDA 10.2 or above. The Docker route is the least configurable and the least informative: docker run -it --network host jittor/jittor for CPU, jittor/jittor-cuda with --gpus all for CUDA, and a port-mapped variant for Mac and Windows.
The Constraint That Matters Most: A Runtime Compiler in Your Dependency Chain
The design decision that makes Jittor interesting is also the one that will disqualify it for many teams. Because the framework and its operators are compiled just-in-time, the machine that runs your model needs a working compiler toolchain and enough resources to compile. The README's own manual install instructions require g++ 5.4 or higher, or clang++-8, plus libomp-dev. That is a heavier deployment surface than a wheel that ships prebuilt kernels. It also means the failure modes are compiler failures, not Python exceptions. A version mismatch between cc_path and the headers on the machine will surface during a test run, not at import time. The README's suggested verification sequence is telling: test_example, then test_cuda, then test_resnet, with a note that the ResNet18 test requires 6G of GPU RAM. That is a real floor. If your target device is a small GPU or a CPU-only edge box, the framework's own integrity test does not fit, and the README does not offer a smaller substitute. There is also no stated ABI stability guarantee in the material provided, so shipping compiled artifacts across machines is not something I can confirm is supported.
Jittor Versus PyTorch: Same Surface, Opposite Bet on Kernels
PyTorch ships a fixed set of precompiled kernels and expects you to use them; when you need something new, you write a C++ or CUDA extension and build it out of band. Jittor inverts that. The operator set is generated at runtime from Python-level definitions, so a new op is a Python definition rather than a separate build target. The trade is clear. PyTorch gives you predictable startup, a huge ecosystem of packages that assume its ABI, and a deployment story that does not need a compiler. Jittor gives you specialization and a shorter path from idea to kernel, at the cost of runtime compilation and a much smaller set of third-party packages. Neither is strictly better. If your work is standard architectures on standard hardware, PyTorch's fixed kernels are already fast and you gain nothing from JIT. If your work is a new operator that no framework ships, Jittor's meta-operator path removes an entire toolchain from your loop. The README also lists model libraries for image recognition, detection, segmentation, generation, differentiable rendering, geometric learning, and reinforcement learning, which suggests the project has invested in reproducing published work rather than only in the core engine. It does not give package counts or compatibility claims, so treat that list as a starting point for your own inspection.
Maintenance, Releases, and the Apache-2.0 Question
The repository is not archived, the last push is dated 2026-09-10, and the most recent release is 1.3.10.0 from 2025-07-28, following 1.3.9.10 and 1.3.9.9 in mid-2024. That is a slow but continuing cadence, and the version numbering (four components, with a leading 1.3) suggests patch releases within a stable line rather than frequent breaking changes. The project is Apache-2.0, which permits commercial use and modification and includes a patent grant. That is the permissive end of the spectrum, and it is a genuine advantage over copyleft alternatives if you plan to ship a modified version. I am not a lawyer and this is not legal advice; if you modify and redistribute Jittor, read the Apache-2.0 terms yourself, particularly the notice and attribution requirements. The maintenance cost you should budget for is not the license. It is the compiler. Every machine that runs Jittor needs a compatible g++ or clang++ and, for GPU work, a matching nvcc. That is an ongoing operational item, not a one-time install step, and it is the reason a Docker image is offered as a first-class install path.
Editorial conclusion
Adopt Jittor if you are doing research that needs custom operators written in Python and compiled at runtime, and you are willing to run the manual install path with a chosen compiler (g++, clang++-8, or icc) plus an explicit nvcc_path. Do not adopt it if you need a stable ABI for shipping binaries, a large third-party package ecosystem, or a team that has never compiled anything. Verify first: run python3.7 -m jittor.test.test_example, then test_cuda, then test_resnet on your actual hardware, and confirm your Python is at least 3.7 on Linux (3.8 on Windows). If test_resnet fails, you have found your answer before writing a single model.
Community notes