orjson review
orjson is a compiled JSON encoder and decoder for CPython. dumps returns UTF-8 bytes and natively handles dataclasses, datetime values, UUIDs, enums, and NumPy arrays when the matching option is enabled; loads accepts bytes, bytearray, memoryview, or text. Version 3.12.0 rewrites the serialization implementation, adds Python 3.15 wheels, and stops publishing ppc64le and s390x wheels. It deliberately leaves file I/O and JSON Lines framing to your code.
orjson 3.12.0 installed in 0.2 seconds as a 1 MB package with 0 dependencies, typed APIs, and 0 pip-audit findings in our sandbox. Install it after profiling confirms JSON cost and bytes output fits the boundary; avoid it on unsupported runtimes or architectures and where stdlib compatibility matters more than encoder speed.
We installed it
| Install | ✓ · 0.2s | 1 package on disk · 1 MB |
| Import | ✓ | import orjson in 0.12s · compiled extensions · py.typed · requires Python >=3.10 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does orjson install cleanly?
Yes. In a fresh container with an empty cache, pip install orjson finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does orjson need to run?
Python >=3.10, and a platform wheel with compiled extensions. In our run import orjson succeeded in 0.12s, and the package ships py.typed for type checkers.
orjson or ujson: which should you use?
ujson: Choose it when a compiled JSON implementation with a more text-like migration path fits an existing codebase. orjson 3.12.0 installed in 0.2 seconds as a 1 MB package with 0 dependencies, typed APIs, and 0 pip-audit findings in our sandbox.
When should you not use orjson?
The application runs on PyPy, embedded Android or iOS Python, or PEP 554 subinterpreters; the README says these targets are unsupported.
Discussed on
- hnJSON extra uses orjson instead of ujson (2019)69 points
- hnorjson: Fast, correct Python JSON lib (supports dataclasses, datetimes, numpy)4 points
- hnOrjson no more open issue tracker or pull requests due to signal-to-noise ratio3 points
- hnorjson v3, fast Python JSON library supporting dataclasses, numpy3 points
Use it if
- Profiling shows JSON encode or decode time is material in a CPython service or data pipeline.
- Returning bytes fits your web framework, socket, cache, or file-writing boundary.
- You need direct serialization of dataclasses, UUIDs, datetime values, or NumPy arrays with explicit options.
- Strict UTF-8 input and rejection of out-of-range integers are useful correctness checks for your payloads.
- The application runs on PyPy, embedded Android or iOS Python, or PEP 554 subinterpreters; the README says these targets are unsupported.
- You need ppc64le or s390x wheels for the current release; version 3.12.0 stopped publishing them.
- Callers require json.dumps-compatible text output and keyword arguments such as indent levels or ensure_ascii; orjson returns bytes and uses option flags.
- A source build is unavoidable but Rust and a C compiler are unavailable; the package ships a compiled extension and source builds need that toolchain.
- The workload is not proven JSON-bound; replacing the standard library adds a binary dependency without fixing network, database, or object-construction costs.
Setup reality
Our clean Python 3.12 install of orjson 3.12.0 took 0.2 seconds and left 1 package occupying 1 MB. import orjson completed in 0.12 seconds. The wheel has a compiled .so extension, declares 0 direct dependencies, requires Python 3.10 or newer, and ships py.typed. pip-audit reported 0 known vulnerabilities in our sandbox.
The first migration surprise is the return type: orjson.dumps produces bytes, whereas json.dumps produces str. Many HTTP frameworks accept bytes directly; text-only interfaces need an explicit UTF-8 decode. loads accepts both byte-oriented inputs and str. The package provides no open-file helper and no JSON Lines reader, so your code owns file handles, newlines, and record boundaries.
Serialization choices are bitwise option flags. OPT_NAIVE_UTC changes naive datetime output, OPT_NON_STR_KEYS permits selected key types, and OPT_SERIALIZE_NUMPY handles supported arrays. Non-string keys can collapse into the same JSON key after conversion. A default callback must raise TypeError for an object it cannot handle, otherwise Python's implicit None becomes JSON null and silently changes the value.
The call holds the GIL for its duration, so threads do not turn one large encode into parallel CPU work. Current wheels cover the mainstream CPython platforms listed in the README, but 3.12.0 removed ppc64le and s390x builds. If pip falls back to source, Rust and a C compiler enter the build path. Benchmark your own documents before changing serializers; the measured install proves packaging and import, not an application speedup.
Patterns
Encode to UTF-8 bytes and decode again encode-json
import orjson
payload = orjson.dumps({'status': 'ok'})
assert isinstance(payload, bytes)dumps returns bytes, not str. Pass the bytes through when the destination accepts them instead of decoding and re-encoding.
Write one JSON record to a file decode-json
value = orjson.loads(b'{"count": 3}')The library does not manage files. OPT_APPEND_NEWLINE avoids concatenating a second immutable bytes object for JSON Lines output.
Serialize timezone-aware datetimes format-output
data = orjson.dumps(value, option=orjson.OPT_INDENT_2 | orjson.OPT_APPEND_NEWLINE)OPT_NAIVE_UTC treats a datetime without tzinfo as UTC. Decide whether that assumption is valid before enabling it globally.
Encode supported NumPy arrays encode-datetime
data = orjson.dumps(event, option=orjson.OPT_NAIVE_UTC | orjson.OPT_UTC_Z)OPT_SERIALIZE_NUMPY handles supported contiguous arrays. Validate dtype and shape expectations at the API boundary.
Convert Decimal through a default callback encode-numpy
data = orjson.dumps(array, option=orjson.OPT_SERIALIZE_NUMPY)Raise TypeError for every unhandled type. Falling off the function returns None, which orjson encodes as null.
Permit selected non-string dictionary keys encode-custom-type
def default(value):
if isinstance(value, Decimal):
return str(value)
raise TypeError
data = orjson.dumps(record, default=default)Converted keys can collide, such as 1 and '1'. The later JSON member may overwrite the earlier value when decoded.
Reject integers unsafe for JavaScript allow-non-string-keys
data = orjson.dumps(mapping, option=orjson.OPT_NON_STR_KEYS)OPT_STRICT_INTEGER caps integers at 53 bits. Without it, orjson accepts signed and unsigned values within its 64-bit limit.
Return readable two-space JSON enforce-safe-integers
data = orjson.dumps(record, option=orjson.OPT_STRICT_INTEGER)Only a 2-space indentation option is provided. Arbitrary indent widths and ensure_ascii behavior from json.dumps are unavailable.
Embed trusted pre-encoded JSON sort-object-keys
data = orjson.dumps(record, option=orjson.OPT_SORT_KEYS)Fragment inserts bytes as JSON without validation or escaping. Use it only with content already produced and trusted as valid JSON.
Map decoding failures to client errors embed-json-fragment
cached = orjson.dumps({'id': 42})
body = orjson.dumps({'item': orjson.Fragment(cached)})JSONDecodeError identifies malformed UTF-8 or JSON. Do not echo an entire untrusted request body in the response or logs.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| ujson | PyPI | Choose it when a compiled JSON implementation with a more text-like migration path fits an existing codebase. |
| msgspec | PyPI | Choose it when typed structural decoding and validation matter alongside fast JSON and MessagePack. |
| simplejson | PyPI | Choose it for a mature stdlib-shaped API with decimal support and fewer binary-platform assumptions. |
More utils guides
lru-cache · type-fest · ajv · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

