Library / SDK
joblib/joblib avatar
joblib/joblib

joblib: caching, parallel loops and persistence for Python functions

Computing with Python functions.

4,399 stars487 forksPythonBSD-3-Clause

At a glance

What is it?
joblib wraps plain Python functions with disk-backed memoization, process-based parallelism and a NumPy-aware serializer. The README covers installation and contribution, but the documented behaviour of Memory and Parallel lives in the docs site, so verify the details there before adopting it.
Who is it for?
Adopt joblib when you have pure Python functions whose results are expensive to recompute, or loops that release the GIL, and you want disk caching or process parallelism without a cluster. Do not adopt it for I/O-bound concurrency or distributed execution across machines; the README points to Dask for that.
Can I use it commercially?
Yes. BSD-3-Clause 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 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem joblib targets: repeated work inside a single Python process

A Python function that reads a large array, fits a model or parses a document will redo that work every time it is called. The usual answers are manual caching, a separate tool such as Redis, or restructuring the program. joblib takes a different route: it treats the function call itself as the unit of work. The pyproject.toml describes the package as "Lightweight pipelining with Python functions", which is the most accurate one-line summary available. The intended audience is developers and researchers, per the classifiers, and the package is marked Production/Stable.

Two distinct problems sit under that description. The first is memoization: call a function twice with equal arguments and the second call should return the stored result rather than recompute it. The second is parallelism: run many independent calls of the same function across CPU cores. Both are exposed through the same object, a function wrapper, which is why the library feels smaller than the sum of its parts. It is not a workflow engine and does not schedule tasks across machines on its own.

How Memory and Parallel actually work

The mechanism is serialization plus a function wrapper. joblib ships its own vendored copy of loky for process management, and its only hard dependency is cloudpickle >= 3.0. That combination matters: cloudpickle can serialize function objects that the standard pickle module cannot, including lambdas and functions defined in a REPL or notebook. The README states that joblib can efficiently dump and load NumPy arrays without requiring NumPy to be installed, so the serialization layer inspects array-like objects and stores their buffers separately.

For caching, joblib hashes the function and its arguments to derive a key, then writes the result to a directory on disk. On a later call with the same key, it loads the stored object instead of executing the body. The examples directory contains memory_basic_usage.py and nested_parallel_memory.py, which suggests the two features are meant to compose. For parallelism, joblib spawns worker processes through loky and dispatches calls to them; the README notes an optional dependency on psutil "to mitigate memory leaks in parallel worker processes", which is an admission that long-lived workers can accumulate memory. The parallel backend can also target Dask distributed, but distributed is not required and the oldest supported version is 2022.8.1.

Installing joblib and running a first cached computation

The README gives a single install command that works from any directory. Python 3.10 or newer is required, and cloudpickle is pulled in automatically.

bash
pip install joblib

The README also shows an editable install from a source checkout, which is what you use if you want to run the examples against your own checkout rather than the released package.

bash
pip install -e .

Once installed, the examples directory is the place to start. It contains memory_basic_usage.py, nested_parallel_memory.py, parallel_generator.py, parallel_memmap.py, parallel_random_state.py and serialization_and_wrappers.py. Running one of those files against your installed joblib shows the caching and parallel behaviour directly, and the README does not reproduce their contents, so read the file you intend to run before executing it. The Makefile shows how the project itself runs its tests, which is also the quickest way to confirm that your environment can spawn worker processes.

bash
pip install joblib[test]
pytest joblib

The first command pulls in the test extras listed in pyproject.toml, including pytest. The second runs the suite from the root of the project. If those pass, the process-based parts of joblib work on your machine.

Cache invalidation and process startup are the real limits

The caching layer keys on the function and its arguments, so a function that depends on external state (a file on disk, a global variable, the current time) will return stale results when that state changes. Nothing in the README or pyproject.toml documents automatic invalidation for those cases. The workaround is to pass the changing value as an argument so it enters the hash, or to clear the cache directory manually. This is the single most common way joblib surprises people.

Parallelism has a cost curve. loky starts processes, and each process imports your module. For functions that take milliseconds, the startup and serialization overhead can exceed the computation, so a plain loop is faster. The library is also the wrong tool for I/O-bound work: the topics list includes threading, but the documented parallel execution is process-based, and processes do not share memory, so large arguments are copied to workers. If your bottleneck is network or disk latency rather than CPU, asyncio or a thread pool fits better.

There is a test escape hatch worth knowing about. The Makefile defines a target that disables multiprocessing entirely:

bash
export JOBLIB_MULTIPROCESSING=0 && pytest joblib

If a test suite behaves differently under that variable, the problem is likely in how your objects serialize rather than in the parallel scheduling.

joblib versus pickle, and versus Dask

The most frequent comparison is with pickle, and the difference is not just speed. Standard pickle serializes objects but cannot handle lambdas or functions defined interactively. joblib depends on cloudpickle to cover those cases, and it adds array-aware handling so NumPy buffers are written efficiently rather than through the generic object protocol. The practical consequence: a joblib dump of an array-heavy object is usually smaller and faster to load than the equivalent pickle file, and the file may not be readable by a plain pickle.load if joblib used its array-aware path. That is a portability trade-off, not a free win. The README also mentions an optional python-lz4 dependency as "a faster alternative to zlib and gzip for compressed serialization", so compression is configurable but not installed by default.

The Dask comparison is about scope. joblib runs work inside one machine, using processes it manages. Dask distributed schedules tasks across a cluster and provides its own dashboard and scheduler. joblib can use Dask as a backend, and the README lists distributed as an optional dependency with a minimum version of 2022.8.1, so the two are not mutually exclusive. If your data already lives on a cluster, or you need to survive a worker dying mid-job, Dask is the layer that handles it. joblib is the smaller tool for a laptop or a single server.

Maintenance, upgrade cost and the BSD-3-Clause licence

The repository is not archived, and the last push was on 2026-09-22. Recent releases are 1.6.0 on 2026-08-31, 1.5.3 on 2025-12-15 and 1.5.2 on 2025-08-27, so the release cadence is roughly one minor version per year with patch releases in between. The CHANGES.rst file is the place to check before upgrading; the README states that changes are listed there and must be updated manually, with a git log command offered to generate the lines. That is a manual process, which means the changelog is only as complete as the maintainers made it.

Upgrade cost is low for the core API. The package requires Python >= 3.10, which is the main constraint: dropping an older interpreter is a breaking change for anyone still on 3.9. The dependency floor is cloudpickle >= 3.0. The licence is BSD-3-Clause, declared in both pyproject.toml and LICENSE.txt, which permits commercial use and modification provided the copyright notice and licence text are retained. That is a permissive licence, not a copyleft one, so it does not force you to publish your own code. This is a description of the licence text, not legal advice; check LICENSE.txt for the exact terms.

Editorial conclusion

Adopt joblib when you have pure Python functions whose results are expensive to recompute, or loops that release the GIL, and you want disk caching or process parallelism without a cluster. Do not adopt it for I/O-bound concurrency or distributed execution across machines; the README points to Dask for that. Before relying on Memory, verify what happens on a cache miss and where the cache directory lives, and check the changelog for the 1.6.0 release notes since the README does not document cache eviction or rollback.

Frequently asked questions

What is joblib used for?

It wraps Python functions to cache their results on disk and to run many calls in parallel across processes. The pyproject.toml describes it as "Lightweight pipelining with Python functions".

Which is better, pickle or joblib?

They solve different problems. Pickle serializes objects but cannot handle lambdas or interactively defined functions, while joblib depends on cloudpickle to cover those and adds efficient dumping and loading of NumPy arrays. joblib output may not be readable by a plain pickle.load when its array-aware path is used.

Is joblib part of Python?

No. It is a separate package distributed on PyPI and installed with pip install joblib. The README states the only hard dependency is cloudpickle >= 3.

How do I install joblib?

Run pip install joblib from any directory, as the README shows. It requires Python 3.10 or newer, and an editable install from a source checkout uses pip install -e .

How do I use joblib to save a model?

The README describes joblib as able to efficiently dump and load NumPy arrays, and the examples directory includes serialization_and_wrappers.py. The README itself does not give a save/load snippet, so check that example file for the exact calls.

How do I use joblib parallel?

Wrap calls in Parallel and delayed, as shown in the examples such as parallel_generator.py and parallel_random_state.py. n_jobs controls how many worker processes loky starts, and n_jobs=1 runs the work in the calling process.

Official sources

  1. joblib/joblib on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/joblib-joblib.svg)](https://hysenlabs.com/projects/joblib-joblib)