JAX: Composable transformations for Python and NumPy programs
Composable transformations of Python+NumPy programs: differentiate, vectorize, JIT to GPU/TPU, and more.
At a glance
- What is it?
- JAX is a Python library that combines NumPy-style array computing with automatic differentiation, JIT compilation, and vectorization. This review covers its core transformations, scaling modes, and sharp edges for engineers considering adoption.
- Who is it for?
- Adopt JAX if your work centers on differentiable numerical programs and you need GPU or TPU acceleration with automatic batching and compilation. The library's composable transformations are unmatched for research and production models that require custom gradients or per-example gradients.
- 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 JAX solves
JAX addresses a specific pain point in numerical computing: writing code that runs efficiently on accelerators while keeping the expressiveness of Python and NumPy. Traditional NumPy runs on CPU, and moving to GPU or TPU often requires rewriting code in a different framework or managing device transfers manually. JAX lets you write ordinary Python functions that operate on NumPy-like arrays, then apply transformations that compile, differentiate, or vectorize them. The intended user is a researcher or engineer who needs high-performance numerical computation, especially in machine learning, without abandoning the Python ecosystem. The README positions JAX as an extensible system for composable function transformations, not just a faster NumPy. The core value is that you can take a function that computes a loss, differentiate it with grad, compile it with jit, and vectorize it with vmap, all in a few lines of code.
How grad, jit, and vmap compose
The three primary transformations are grad, jit, and vmap, and they compose arbitrarily. Grad performs reverse-mode automatic differentiation, and it works through Python control flow like loops, branches, recursion, and closures. The README shows that grad can differentiate a function with an if statement, re-evaluating the function to handle the branch. You can take derivatives of derivatives to any order. Jit compiles a pure function using XLA, fusing element-wise operations for speed. The README notes that jit constrains Python control flow, directing users to a tutorial on control flow with JIT. Vmap maps a function along array axes, but instead of looping, it pushes the vectorization down to primitive operations, turning matrix-vector multiplies into matrix-matrix multiplies. The key point is composition: the README demonstrates jax.jit(jax.vmap(jax.grad(loss))) to get compiled, per-example gradients. This composition is the heart of JAX's design, and it is what distinguishes it from libraries that offer these features separately.
Scaling across devices: three modes
JAX offers three scaling modes, each with a different trade-off between control and convenience. The first is compiler-based automatic parallelization, where you write code as if running on a single global machine and the compiler decides how to shard data and partition computation. The second is explicit sharding with automatic partitioning, where you still have a global view but specify data shardings in JAX types, inspectable via jax.typeof. The third is manual per-device programming, where you have a per-device view and use explicit collectives for communication. The README includes a table showing that auto mode has no explicit sharding or collectives, explicit mode adds sharding but no collectives, and manual mode has both. This range lets you start with the simplest approach and move to more control when needed. The example uses jax.make_mesh to create a mesh with a data axis, then shards parameters for FSDP-style training and data for batch parallelism. The result is that jax.jit(jax.grad(loss)) automatically parallelizes the gradient computation across devices. This is a significant feature for large-scale training, but it also introduces complexity in understanding sharding and mesh configurations.
Installation and getting started
The README does not include explicit installation commands, but it links to an install guide. Based on the project structure, JAX is distributed on PyPI as the package jax. A typical installation would be pip install jax, but for GPU or TPU support, you likely need additional packages like jaxlib or jax-cuda12-plugin. The README's examples assume you have a working JAX environment and access to accelerators. To run the first example, you would import jax and jax.numpy as jnp, define a predict function, then compute a compiled gradient function with jax.jit(jax.grad(loss)). The code snippets are self-contained and can be executed in a Python script or notebook. The README also mentions using %timeit in a notebook to compare jitted and non-jitted functions. For a simple CPU setup, pip install jax should work, but for GPU, you need to match the CUDA version. The install guide is the authoritative source, and the README warns that this is a research project with sharp edges, so expect to troubleshoot.
Sharp edges and limitations
JAX is not a drop-in replacement for NumPy. The README explicitly warns about sharp edges and links to a common gotchas notebook. One limitation is that jit constrains the kind of Python control flow a function can use. While grad supports arbitrary control flow, jit requires that control flow be traceable or explicitly handled with constructs like jax.lax.cond or jax.lax.scan. Another limitation is that JAX arrays are immutable, so in-place operations like x[i] += 1 need to be rewritten using functional updates like x.at[i].add(1). This can be a significant rewrite for existing NumPy code. The README's examples avoid these issues by using pure functions, but real-world code often has side effects or complex control flow. Also, JAX uses XLA, which may not support every NumPy operation, and compilation can introduce overhead for small functions. The README notes that the project is a research product, not an official Google product, so you should expect breaking changes and evolving APIs. These limitations mean JAX is best suited for new code written with JAX's constraints in mind, not for porting large legacy NumPy programs.
Alternatives and how JAX differs
The most direct alternative is PyTorch, which also provides automatic differentiation and GPU support. The key difference is that PyTorch uses a tape-based autograd system that records operations during execution, while JAX uses function transformation: you define a pure function and then apply grad to get a new function. This means JAX can compile the entire computation graph with jit, and it can vectorize with vmap, which are not native to PyTorch. PyTorch has its own compilation features like torch.compile and vmap support, but they are less central to the design. Another alternative is TensorFlow with tf.function, which also uses graph compilation, but JAX's functional style and composability are more explicit. For numerical computing without machine learning, you might use Numba, which compiles NumPy-like code with a decorator, but Numba does not provide automatic differentiation or multi-device scaling. The README does not mention alternatives, but the architecture is clear: JAX's transformations are first-class and composable, whereas other frameworks treat them as add-ons. This makes JAX particularly strong for research where you need custom gradients or per-example gradients.
Maintenance and license
JAX is licensed under Apache-2.0, which is permissive for commercial use, but it is not an official Google product. The README explicitly states that it is a research project and expects sharp edges. The repository is actively maintained, with recent releases including v0.11.1 in August 2026 and v0.11.0 in July 2026. The last push was on 2026-08-17, indicating ongoing development. This activity means you should expect frequent updates, which can introduce breaking changes. The changelog is linked for tracking. For maintenance costs, you need to factor in the learning curve for JAX's functional style and the need to stay updated with releases. The license allows you to modify and use the code, but you should check the full terms for any patent or attribution clauses. Since it is a research project, community support is through GitHub issues, and there is no commercial support. For production use, you should have a strategy for pinning versions and testing upgrades. The active release cadence suggests a healthy project, but it also means you cannot assume stability.
Editorial conclusion
Adopt JAX if your work centers on differentiable numerical programs and you need GPU or TPU acceleration with automatic batching and compilation. The library's composable transformations are unmatched for research and production models that require custom gradients or per-example gradients. Do not adopt JAX if you rely on unmodified NumPy codebases with complex in-place operations or extensive Python control flow inside hot loops, as these will need rewriting. Before committing, verify that your target hardware (NVIDIA GPU, TPU, or CPU) is supported by the installed XLA version, and test your specific workloads for compilation overhead and memory usage. The project is explicitly a research effort, not an official Google product, so budget for sharp edges and frequent updates.
Community notes