orjson Python
Treat JSON as a wire/storage contract. Decide the accepted Python domain, JSON
shape, text/bytes boundary, datetime and integer policy, key ordering, and error
behavior before selecting options.
Boundary
Use this skill when the project imports orjson or explicitly requests it. Do
not introduce orjson solely from a vague performance claim; benchmark the real
payload and preserve the surrounding interface. orjson encodes/decodes values;
it does not own file I/O, JSON Lines framing, schema validation, HTTP content
types, or format/comment preservation.
Know the values
| Object |
Contract |
orjson.dumps(value, ...) |
Returns UTF-8 JSON as bytes, never str. |
orjson.loads(data) |
Accepts UTF-8 bytes, bytearray, memoryview, or str; returns ordinary Python JSON values. |
default(obj) |
Converts one unsupported object to a supported value or raises TypeError. |
option bitmask |
Explicitly changes encoding semantics; combine flags with ` |
JSONEncodeError |
Serialization contract failure; a TypeError subclass. |
JSONDecodeError |
Invalid input/type/depth failure; compatible with json.JSONDecodeError/ValueError. |
Fragment |
Injects already-serialized JSON without validation/escaping; a trust boundary. |
Read serialization contracts before replacing
stdlib json, encoding temporal values, or accepting arbitrary keys.
Ordered workflow
- Recover the external contract: JSON shape, field names, accepted input
types, byte/text owner, newline/framing, datetime/timezone form, number
limits, ordering, and error mapping.
- Inspect the installed orjson version and the existing adapter. Preserve a
public
str return only by decoding once at that boundary; preserve bytes
for binary HTTP/file/socket APIs.
- Start with no options. Add one option only for a named contract requirement,
not because an example includes it.
- Use native supported types where their semantics match. Add a narrow
default dispatcher for project-owned unsupported types; never return an
unsupported object or stringify every unknown value.
- Keep I/O/framing outside
dumps and loads. Add exactly one newline per
JSON-lines record; do not parse an entire JSONL file as one JSON value.
- Map encode/decode errors at the application boundary without swallowing the
input location/cause or leaking payloads.
- Test exact decoded structure plus byte-level requirements such as newline,
key order, timezone spelling, or rejection behavior.
Decision table
| Requirement |
Action |
| Binary response/body/file API |
Pass dumps bytes directly. |
Text API explicitly requires str |
Decode UTF-8 once at the outer boundary. |
| Input already bytes-like |
Pass it to loads; do not decode first. |
| Pretty human file |
Use indentation only if whitespace is contractual; append newline deliberately. |
| JSON Lines |
Encode each record separately and delimit records; do not wrap in an array. |
Datetime contract requires UTC Z |
Normalize awareness/policy, then use the verified UTC option or explicit adapter. |
| Naive datetime has no declared timezone |
Reject or normalize before encoding; do not silently invent local/UTC meaning. |
| Non-string dict keys are part of the schema |
Confirm supported key domains and collision risks before the non-string-key option. |
| JavaScript-safe integer range is required |
Enable strict integer behavior or validate at the domain boundary. |
| Deterministic lexical key order is required |
Use sorted keys and test bytes; do not call it canonical JSON without a full canonicalization spec. |
| Unknown object |
Serialize through a type-specific default; otherwise raise. |
Canonical boundary
from decimal import Decimal
from pathlib import Path
from typing import Any
import orjson
def default(value: Any) -> Any:
if isinstance(value, Decimal):
return format(value, "f") # schema declares a decimal string
if isinstance(value, Path):
return value.as_posix() # schema declares a POSIX path string
raise TypeError(f"unsupported type: {type(value).__name__}")
def encode_event(event: object) -> bytes:
return orjson.dumps(event, default=default)
def decode_event(payload: bytes | bytearray | memoryview | str) -> dict[str, Any]:
value = orjson.loads(payload)
if not isinstance(value, dict):
raise ValueError("event JSON must be an object")
return value
loads validates JSON syntax, not the application shape. Validate the returned
object separately. default normally sees only types orjson does not already
serialize natively; dataclasses and datetimes need passthrough options before a
custom handler can override their native representation. A default function
must raise TypeError for unsupported values so contract errors remain visible.
High-risk options and integration
- Option flags are not general best practices. Each changes observable output
or accepted types and needs a protecting test.
- Native datetime serialization does not decide the business meaning of naive
values. Establish timezone policy before encoding.
- Non-string keys can serialize different Python keys to the same JSON member
name; reject ambiguity when round-tripping or signatures matter.
- Pretty printing, key sorting, and newline flags add work. Use them for a
contract, not a generic speed path.
Fragment trusts its bytes as JSON and skips validation/escaping. Accept it
only from a controlled serialized source, never raw user text.
- In web frameworks, adapt to their response class/renderer contract. Avoid a
second
json.dumps around orjson bytes and set the JSON media type.
Read options and integration for these
branches.
Error and verification contract
Invalid input, unsupported objects, non-finite values, excessive depth, integer
limits, and invalid UTF-8 need explicit behavior. Do not return {}/None on a
decode failure unless that fallback is a documented domain rule. Test malformed
JSON and unsupported types, not only round trips; a lossy encoder can round-trip
its own mistake.
Read testing JSON behavior. This foundry did not have
orjson installed during authoring, so its cases use static/source evidence and
must not be described as local runtime validation. Completion requires exact
outer type (bytes or str), declared temporal/number/key semantics, narrow
custom encoding, correct framing, explicit shape validation, and negative tests
for malformed and unsupported input.
References
- Serialization contracts
- Options and integration
- Testing JSON behavior
1---2name: orjson-python3description: Use for writing, reviewing, debugging, or testing Python JSON serialization and deserialization with orjson, including bytes/text boundaries, datetimes, dataclasses, NumPy, custom default handlers, option flags, strictness, and web/file integration. Do not use for JSON Schema validation, format-preserving JSON edits, streaming I/O frameworks, or choosing a JSON library when orjson is not requested or present.4---56# orjson Python78Treat JSON as a wire/storage contract. Decide the accepted Python domain, JSON9shape, text/bytes boundary, datetime and integer policy, key ordering, and error10behavior before selecting options.1112## Boundary1314Use this skill when the project imports orjson or explicitly requests it. Do15not introduce orjson solely from a vague performance claim; benchmark the real16payload and preserve the surrounding interface. orjson encodes/decodes values;17it does not own file I/O, JSON Lines framing, schema validation, HTTP content18types, or format/comment preservation.1920## Know the values2122| Object | Contract |23|---|---|24| `orjson.dumps(value, ...)` | Returns UTF-8 JSON as `bytes`, never `str`. |25| `orjson.loads(data)` | Accepts UTF-8 `bytes`, `bytearray`, `memoryview`, or `str`; returns ordinary Python JSON values. |26| `default(obj)` | Converts one unsupported object to a supported value or raises `TypeError`. |27| `option` bitmask | Explicitly changes encoding semantics; combine flags with `|`. |28| `JSONEncodeError` | Serialization contract failure; a `TypeError` subclass. |29| `JSONDecodeError` | Invalid input/type/depth failure; compatible with `json.JSONDecodeError`/`ValueError`. |30| `Fragment` | Injects already-serialized JSON without validation/escaping; a trust boundary. |3132Read [serialization contracts](references/data-contracts.md) before replacing33stdlib `json`, encoding temporal values, or accepting arbitrary keys.3435## Ordered workflow36371. Recover the external contract: JSON shape, field names, accepted input38 types, byte/text owner, newline/framing, datetime/timezone form, number39 limits, ordering, and error mapping.402. Inspect the installed orjson version and the existing adapter. Preserve a41 public `str` return only by decoding once at that boundary; preserve bytes42 for binary HTTP/file/socket APIs.433. Start with no options. Add one option only for a named contract requirement,44 not because an example includes it.454. Use native supported types where their semantics match. Add a narrow46 `default` dispatcher for project-owned unsupported types; never return an47 unsupported object or stringify every unknown value.485. Keep I/O/framing outside `dumps` and `loads`. Add exactly one newline per49 JSON-lines record; do not parse an entire JSONL file as one JSON value.506. Map encode/decode errors at the application boundary without swallowing the51 input location/cause or leaking payloads.527. Test exact decoded structure plus byte-level requirements such as newline,53 key order, timezone spelling, or rejection behavior.5455## Decision table5657| Requirement | Action |58|---|---|59| Binary response/body/file API | Pass `dumps` bytes directly. |60| Text API explicitly requires `str` | Decode UTF-8 once at the outer boundary. |61| Input already bytes-like | Pass it to `loads`; do not decode first. |62| Pretty human file | Use indentation only if whitespace is contractual; append newline deliberately. |63| JSON Lines | Encode each record separately and delimit records; do not wrap in an array. |64| Datetime contract requires UTC `Z` | Normalize awareness/policy, then use the verified UTC option or explicit adapter. |65| Naive datetime has no declared timezone | Reject or normalize before encoding; do not silently invent local/UTC meaning. |66| Non-string dict keys are part of the schema | Confirm supported key domains and collision risks before the non-string-key option. |67| JavaScript-safe integer range is required | Enable strict integer behavior or validate at the domain boundary. |68| Deterministic lexical key order is required | Use sorted keys and test bytes; do not call it canonical JSON without a full canonicalization spec. |69| Unknown object | Serialize through a type-specific `default`; otherwise raise. |7071## Canonical boundary7273```python74from decimal import Decimal75from pathlib import Path76from typing import Any7778import orjson798081def default(value: Any) -> Any:82 if isinstance(value, Decimal):83 return format(value, "f") # schema declares a decimal string84 if isinstance(value, Path):85 return value.as_posix() # schema declares a POSIX path string86 raise TypeError(f"unsupported type: {type(value).__name__}")878889def encode_event(event: object) -> bytes:90 return orjson.dumps(event, default=default)919293def decode_event(payload: bytes | bytearray | memoryview | str) -> dict[str, Any]:94 value = orjson.loads(payload)95 if not isinstance(value, dict):96 raise ValueError("event JSON must be an object")97 return value98```99100`loads` validates JSON syntax, not the application shape. Validate the returned101object separately. `default` normally sees only types orjson does not already102serialize natively; dataclasses and datetimes need passthrough options before a103custom handler can override their native representation. A `default` function104must raise `TypeError` for unsupported values so contract errors remain visible.105106## High-risk options and integration107108- Option flags are not general best practices. Each changes observable output109 or accepted types and needs a protecting test.110- Native datetime serialization does not decide the business meaning of naive111 values. Establish timezone policy before encoding.112- Non-string keys can serialize different Python keys to the same JSON member113 name; reject ambiguity when round-tripping or signatures matter.114- Pretty printing, key sorting, and newline flags add work. Use them for a115 contract, not a generic speed path.116- `Fragment` trusts its bytes as JSON and skips validation/escaping. Accept it117 only from a controlled serialized source, never raw user text.118- In web frameworks, adapt to their response class/renderer contract. Avoid a119 second `json.dumps` around orjson bytes and set the JSON media type.120121Read [options and integration](references/options-integration.md) for these122branches.123124## Error and verification contract125126Invalid input, unsupported objects, non-finite values, excessive depth, integer127limits, and invalid UTF-8 need explicit behavior. Do not return `{}`/`None` on a128decode failure unless that fallback is a documented domain rule. Test malformed129JSON and unsupported types, not only round trips; a lossy encoder can round-trip130its own mistake.131132Read [testing JSON behavior](references/testing.md). This foundry did not have133orjson installed during authoring, so its cases use static/source evidence and134must not be described as local runtime validation. Completion requires exact135outer type (`bytes` or `str`), declared temporal/number/key semantics, narrow136custom encoding, correct framing, explicit shape validation, and negative tests137for malformed and unsupported input.138139## References140141- [Serialization contracts](references/data-contracts.md)142- [Options and integration](references/options-integration.md)143- [Testing JSON behavior](references/testing.md)