Library / SDK
jsonpickle/jsonpickle avatar
jsonpickle/jsonpickle

jsonpickle is pickle wearing a JSON costume, and the README says so

Python library for serializing any arbitrary object graph into JSON. It can take almost any Python object and turn the object into JSON. Additionally, it can reconstitute the object back into Python.

1,320 stars195 forksPythonBSD-3-Clause

At a glance

What is it?
jsonpickle is a BSD licensed Python library for the two-way conversion of complex Python objects and JSON, with optional numpy and pandas handlers, and it builds on top of existing JSON encoders such as simplejson, json and ujson. Its documentation is unusually direct about the security model, stating that the module is not secure and that only trusted data should be decoded.
Who is it for?
jsonpickle suits a team that needs to persist arbitrary Python objects in a form other systems can read, such as a JSON column, an object store or an analytics pipeline, and that is storing and reading back data it controls. It does not suit a service that decodes JSON supplied by users, because the decoding path can execute arbitrary code, and the library says so.
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 last received commits 2 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

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

Editorial analysis

Two way conversion, on top of the encoders you already have

jsonpickle is a library for the two-way conversion of complex Python objects and JSON. The project description puts it more bluntly, a library for serializing any arbitrary object graph into JSON, taking almost any Python object and turning it into JSON, and additionally reconstituting the object back into Python.

What sits underneath matters. The library builds upon existing JSON encoders, such as simplejson, json and ujson, so the JSON generation is delegated to a backend rather than written from scratch, and the interesting work is the part that plain JSON cannot do, which is remembering what class an object was and rebuilding it.

The usage example in the README is short and shows the whole cycle. A dataclass with a single string field is encoded, written to a file, read back and decoded, and the decoded value is asserted equal to the original:

python
import jsonpickle
from dataclasses import dataclass


@dataclass
class Example:
    data: str


ex = Example("value1")
encoded_instance = jsonpickle.encode(ex)
assert encoded_instance == '{"py/object": "__main__.Example", "data": "value1"}'

with open("example.json", "w+") as f:
    f.write(encoded_instance)

with open("example.json", "r+") as f:
    written_instance = f.read()
    decoded_instance = jsonpickle.decode(written_instance)
assert decoded_instance == ex

The library itself has no dependencies beyond the Python standard library, and the project metadata requires Python 3.10 or newer, with classifiers covering 3.10 through 3.14 and the development status marked as Production/Stable.

The audience is a Python developer whose data has to leave Python and come back. That is the whole use case, and the rest of this article is about when it is the right one.

The py/object marker is what makes it reversible

Look at the encoded output in the example, {"py/object": "__main__.Example", "data": "value1"}, and the mechanism is visible.

Plain JSON has no notion of a class, so an encoder that wants to reverse itself has to write the class into the document. The py/object key carries the import path of the type, and the rest of the object is the ordinary JSON representation. On the way back, the decoder reads that key, resolves the path, and constructs the object rather than returning a dict.

That is a small design decision with large consequences, and the reader should be clear about them. First, the output is no longer plain data, it is data plus a program description. Any consumer that expects to read the file as a generic JSON document will see a key it does not understand. Second, the type path is part of the format, so moving a class, renaming a module or restructuring a package changes what previously written files decode into.

The examples directory shows the ways you deal with that in practice. There is changing_class_path.py, which is about exactly this problem, and save_class_to_file.py and custom_handler_context.py for the cases where you want to control the class information or the handler used.

There is also a cross language angle. The README lists jsonpickleJS as a sister project that implemented similar functionality in JavaScript, with its last release in August 2025. That project is the proof that the format is meant to be read outside Python, which is the point of using JSON rather than pickle, and it is also the clearest statement of the contract: a non-Python reader has to understand the py/object convention, or at least tolerate it.

The security section is the part to read first

The README puts a warning right at the top of the document, before the usage section, and it says that jsonpickle can execute arbitrary Python code and points you to the Security section for details.

That section is direct. jsonpickle should be treated the same as the Python stdlib pickle module from a security perspective. The jsonpickle module is not secure. Only unpickle data you trust. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling, and you should never unpickle data that could have come from an untrusted source, or that could have been tampered with.

The mitigation offered is specific: consider signing data with an HMAC if you need to ensure that it has not been tampered with. And then the alternative is stated plainly, that safer deserialization approaches, such as reading JSON directly, may be more appropriate if you are processing untrusted data.

It is worth understanding why jsonpickle cannot be made safe the way plain JSON is. The decoder's job is to reconstruct a class instance, and reconstructing a class instance means importing a module and calling a constructor, and the path it uses to decide what to import is data that came from the document. The same property that makes the format work, round tripping arbitrary objects, is what makes it dangerous with hostile input. The library does not pretend otherwise, and that honesty is a good reason to trust its other documentation.

So the rule for a user is short. If you control the data, jsonpickle is a fine tool. If you do not, it is the wrong tool, and the library says which one to use instead.

The reason to use it is that other tools can read the data

The Why jsonpickle section gives the argument, and it is a data portability argument rather than a convenience one.

Data serialized with Python's pickle, or cPickle, or dill, is not easily readable outside of Python. Using the JSON format, jsonpickle allows simple data types to be stored in a human-readable format, and more complex data types such as numpy arrays and pandas dataframes to be machine-readable on any platform that supports JSON. The example given is that, unlike pickled data, jsonpickled data stored in an Amazon S3 bucket is indexible by Amazon's Athena.

That is the concrete case to weigh. If your data ends up in a column store, an object store, a data lake or a warehouse, then the format determines what can query it later. A pickle blob in S3 is opaque to every service except a Python process that happens to have the right class definitions. A JSON document with a py/object marker is still queryable by Athena, by a SQL engine's JSON functions, by a JavaScript service, by a human with a text editor.

The catch is that the queryable part is the data, not the type information. Athena sees a JSON column and can extract the fields, but the class reconstruction is a Python side concern. That is usually exactly what you want, since the analytics side wants the values and the application side wants the objects, but it is worth being explicit that the two consumers get different things from the same file.

The human readability point is the other half. A file that a person can open, read and diff is a file you can debug, review in a pull request, and inspect when something has gone wrong at three in the morning, and that is worth a great deal.

numpy and pandas need their handlers registered by hand

The library includes built-in numpy and pandas extensions, but they are not active by default, and the reason is that importing numpy and pandas eagerly would defeat the promise of having no dependencies beyond the standard library.

The extension modules live under jsonpickle.ext, and enabling them is a matter of importing and calling register_handlers on each:

python
>>> import jsonpickle.ext.numpy as jsonpickle_numpy
>>> import jsonpickle.ext.pandas as jsonpickle_pandas
>>> jsonpickle_numpy.register_handlers()
>>> jsonpickle_pandas.register_handlers()

The README notes that if you would like to encode sklearn models, numpy arrays, pandas DataFrames, and other numpy and pandas based data, you must enable the numpy and/or pandas extensions by registering their handlers. sklearn is mentioned in the same sentence, which is a hint that the scope of what the extensions cover is broader than the two libraries named in the module names.

For a user this is a small step with a real consequence if you forget it. Without the handlers, a numpy array is not encoded as a numpy array, and on the way back you get something that is not the array you stored. The failure is quiet rather than loud, which is the worst kind, and the register_handlers call is the thing to make sure appears in your application start-up rather than in a module someone remembers to import.

The examples directory includes np_pd_extensions.py, so the pattern to copy is in the repository rather than in your imagination.

Install, encode, and keep the test suite honest

Installation from pip gets the latest stable release:

bash
pip install jsonpickle

And installing from GitHub gets the latest changes:

bash
pip install git+https://github.com/jsonpickle/jsonpickle.git

The development setup is documented in more detail, and it is worth reading because the project supports several Python versions and wants the tests run against all of them. The unit tests are run with pytest through make:

bash
make test

and a tox target runs the tests using all installed and supported Python versions:

bash
make tox

The recommended route is a virtual environment, with an editable install of the development extra:

bash
python3 -mvenv env3
source env3/bin/activate
pip install --editable '.[dev]'
make test

The README also documents a variant that avoids polluting your shell, using a tool called vx to run the command inside the environment, and a fallback for people who cannot use a virtual environment at all, which is pip install .[testing]. The testing requirements themselves are specified in setup.cfg, and the project notes that jsonpickle has no dependencies beyond the standard library, with tox required only for the tox test runner.

The Makefile itself is a small amount of careful engineering, with the CPU count detected differently on macOS than on Linux, a job count clamped to half the machine's CPU count because concurrent jobs share cache and memory bandwidth, and separate targets for the test and benchmark commands. The benchmarking/ directory and jsonpickle_benchmarks.py sit next to a BENCHMARKS.md, and there is a fuzzing/ directory, which for a library whose decoder consumes untrusted input is a reassuring thing to find.

A 4.x stable line with a 5.0 candidate behind it

The release list is worth reading closely, because it is not a simple version sequence. The recent tags are 4.1.4 on 2026-10-15, 4.1.3 on 2026-10-02, and 5.0.0rc2 on 2026-05-28. So the stable line is 4.1.x and it is still receiving patches, while a 5.0 release candidate has been sitting on the branch since May.

That is a project in the middle of a major version transition, and for a library that stores data in a durable format it has a specific implication. The encoded form is the contract between your application and everything that reads the data later, so a major version may change the way class information is represented, and files written by one version may not be intended to be read by the other. Nothing in the README states the compatibility policy, so the practical approach is to pin the version your data is written with and read CHANGES.rst when you decide to move.

The repository supports that kind of care. There is a CHANGES.rst, a RELEASING.md describing how releases are made, a SECURITY.md for reporting problems, and both GitHub Actions and the older Azure Pipelines and AppVeyor configuration files, so the test matrix runs on several platforms.

One small operational note, because it affects how you verify an install. The README explains that while versions before 3.0.1 should still be signed, GPG signing support was removed from PyPI in May 2023. So the pip hash and the package index signature story has changed for new releases, and if your organisation verifies distributions by signature, that is a check to make before you add this to a build pipeline.

The licence is BSD, recorded in the metadata as BSD-3-Clause, which is permissive, but still requires keeping the copyright notice and licence text.

Editorial conclusion

jsonpickle suits a team that needs to persist arbitrary Python objects in a form other systems can read, such as a JSON column, an object store or an analytics pipeline, and that is storing and reading back data it controls. It does not suit a service that decodes JSON supplied by users, because the decoding path can execute arbitrary code, and the library says so. Verify first that the format is readable by the other side of your pipeline, register the numpy and pandas handlers if you use them, and if you must decode data you do not control, sign it with an HMAC or read the JSON directly instead.

Frequently asked questions

Is jsonpickle safe to decode untrusted data?

No. The README states that the module is not secure, that it should be treated the same as the Python stdlib pickle module from a security perspective, and that malicious data can execute arbitrary code during unpickling. It recommends signing data with an HMAC, and says that reading JSON directly may be more appropriate for untrusted data.

How do I install jsonpickle?

With pip install jsonpickle for the latest stable release, or pip install git+https://github.com/jsonpickle/jsonpickle.git for the latest changes. The library itself has no dependencies beyond the Python standard library and requires Python 3.10 or newer.

How do I enable numpy and pandas support in jsonpickle?

Import the extension modules and register their handlers, for example jsonpickle_numpy.register_handlers() and jsonpickle_pandas.register_handlers() from jsonpickle.ext.numpy and jsonpickle.ext.pandas. Without this, numpy arrays and pandas DataFrames are not encoded as such.

Why would I use jsonpickle instead of pickle?

Pickled data is not easily readable outside Python, whereas jsonpickled data stays in a human-readable JSON format that simple data types can be inspected in and complex types such as numpy arrays and pandas dataframes can be read by anything that supports JSON, for example data stored in an Amazon S3 bucket that is then indexed by Amazon's Athena.

How do I run the jsonpickle test suite?

Run make test for the unit tests, which use pytest, and make tox to run the tests across all installed and supported Python versions. The project recommends doing this inside a virtual environment with an editable install of the development extra.

Official sources

  1. jsonpickle/jsonpickle 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/jsonpickle-jsonpickle.svg)](https://hysenlabs.com/projects/jsonpickle-jsonpickle)