# How print_json() Handles JSON Serialization and Syntax Highlighting in Rich

> Discover how Rich's print_json orchestrates JSON serialization and syntax highlighting using the JSON renderable and JSONHighlighter across three architectural layers for beautiful terminal output.

- Repository: [Textualize/rich](https://github.com/Textualize/rich)
- Tags: deep-dive
- Published: 2026-03-06

---

**Rich's `print_json()` function serializes Python objects or raw JSON strings into pretty-printed, syntax-highlighted terminal output by orchestrating the `JSON` renderable class and `JSONHighlighter` across three distinct architectural layers.**

The `print_json()` function in Textualize/rich provides an elegant way to display JSON data with automatic formatting and syntax highlighting. Whether you pass a raw JSON string or a native Python dictionary, the library processes input through a pipeline spanning [`rich/console.py`](https://github.com/Textualize/rich/blob/main/rich/console.py), [`rich/json.py`](https://github.com/Textualize/rich/blob/main/rich/json.py), and [`rich/highlighter.py`](https://github.com/Textualize/rich/blob/main/rich/highlighter.py). Understanding this architecture reveals how Rich achieves its polished, colorized output.

## The Entry Point: Console.print_json()

The API surface resides in [`rich/console.py`](https://github.com/Textualize/rich/blob/main/rich/console.py) at lines 1751-1797, where `Console.print_json()` serves as the primary interface. This method accepts two mutually exclusive inputs: a pre-formatted JSON string via the `json` parameter or a Python object via the `data` parameter.

When the `json` argument is `None`, the method delegates serialization to `JSON.from_data()` to encode the Python value. If a string is provided, the method validates the input type and constructs a `JSON` instance directly from the raw text. This branching logic ensures flexible input handling while maintaining strict type safety before rendering.

## JSON Serialization in rich/json.py

The `JSON` class in [`rich/json.py`](https://github.com/Textualize/rich/blob/main/rich/json.py) manages encoding and pretty-printing logic. In `JSON.__init__` (lines 25-51), the implementation parses the input string using `json.loads()`, then re-serializes it with the specified `indent`, `ensure_ascii`, and other formatting options to ensure consistent output.

For Python objects, `JSON.from_data()` at lines 54-99 performs the initial encoding using `json.dumps()`. This method accepts standard library parameters including `default`, `skip_keys`, `allow_nan`, and `sort_keys`, allowing fine-grained control over how complex Python objects convert to formatted JSON strings before highlighting is applied.

## Syntax Highlighting with JSONHighlighter

Syntax highlighting is implemented by the `JSONHighlighter` class in [`rich/highlighter.py`](https://github.com/Textualize/rich/blob/main/rich/highlighter.py) (lines 106-121). This highlighter extends `RegexHighlighter` to apply color spans matching JSON structures: braces, brackets, booleans, `null`, numbers, and strings.

After the base regex highlighting completes, `JSONHighlighter.highlight()` performs an additional semantic pass to detect object keys. It scans for string literals followed immediately by a colon outside of whitespace, applying the `"json.key"` style to distinguish dictionary keys from ordinary string values. When highlighting is disabled via `highlight=False`, the system instantiates `NullHighlighter` to bypass colorization while preserving formatting.

## Rendering to the Terminal

Finally, `Console.print_json()` forwards the constructed `JSON` renderable to `Console.print()` with `soft_wrap=True` explicitly enabled. This parameter ensures long JSON lines wrap gracefully at word boundaries rather than character boundaries, preserving readability in narrow terminal windows without breaking the logical structure of the highlighted text.

## Practical Code Examples

The following examples demonstrate the flexible input handling and customization options available through the `print_json()` API:

```python
from rich import print_json

# Pretty-print a raw JSON string with default syntax highlighting

print_json('{"name": "Alice", "age": 30, "active": true}')

# Serialize a Python object with custom indentation

data = {"fruits": ["apple", "banana"], "count": 2, "available": None}
print_json(data=data, indent=4)

# Disable highlighting for plain-text output

print_json(data, highlight=False)

# Control Unicode escaping and NaN handling

print_json(
    {"value": "π", "nan": float("nan")},
    ensure_ascii=False,
    allow_nan=False
)

```

## Summary

- **Input Routing**: `Console.print_json()` in [`rich/console.py`](https://github.com/Textualize/rich/blob/main/rich/console.py) accepts either raw JSON strings (`json=`) or Python objects (`data=`), routing them through different initialization paths to ensure proper type handling.
- **Encoding Layer**: The `JSON` class in [`rich/json.py`](https://github.com/Textualize/rich/blob/main/rich/json.py) handles all serialization via `json.dumps()` and `json.loads()`, supporting parameters like `indent`, `ensure_ascii`, `allow_nan`, and `default` callbacks for complex objects.
- **Colorization Engine**: `JSONHighlighter` in [`rich/highlighter.py`](https://github.com/Textualize/rich/blob/main/rich/highlighter.py) applies regex-based colorization and performs a secondary pass to identify object keys using the `"json.key"` style, distinguishing them from string values.
- **Terminal Output**: The final renderable is printed with `soft_wrap=True` to ensure readable formatting regardless of terminal width, completing the pipeline from raw input to highlighted output.

## Frequently Asked Questions

### How does print_json() distinguish between JSON strings and Python objects?

`print_json()` checks the `json` parameter first. If `None`, it calls `JSON.from_data()` in [`rich/json.py`](https://github.com/Textualize/rich/blob/main/rich/json.py) to serialize the Python object provided via `data`. If a string is passed to `json`, the method validates the type and passes it directly to the `JSON` constructor. This mutually exclusive design prevents ambiguity between raw JSON text and Python dictionaries.

### Can I customize the JSON serialization parameters when using print_json()?

Yes. When passing a Python object via the `data` parameter, `JSON.from_data()` forwards standard `json.dumps()` parameters including `indent`, `default`, `sort_keys`, `ensure_ascii`, and `allow_nan`. These control how Python objects are converted to formatted strings, allowing customization of indentation, Unicode escaping, and NaN handling.

### Why are JSON object keys highlighted differently from string values?

The `JSONHighlighter.highlight()` method in [`rich/highlighter.py`](https://github.com/Textualize/rich/blob/main/rich/highlighter.py) performs a secondary pass after initial regex highlighting. It scans for colons positioned immediately after string literals (outside whitespace) and applies the `"json.key"` style to those strings. This distinguishes dictionary keys from regular string values in the final colorized output.

### Is it possible to disable syntax highlighting entirely?

Yes. Pass `highlight=False` to `print_json()`. This causes the `JSON` class to instantiate `NullHighlighter` instead of `JSONHighlighter`, resulting in plain text output without color spans while maintaining the pretty-printed formatting and indentation.