JSON6 for Python

Parse and work with JSON6 files in your Python applications.

TL;DR: Install with pip install json6, then use json6.load() and json6.loads() just like the standard json module.

Installation

The most popular JSON6 library for Python is json6, available on PyPI.

pip

pip install json6

pipenv

pipenv install json6

Poetry

poetry add json6

uv

uv add json6

conda

conda install -c conda-forge json6

1M+

Monthly downloads

Python 3.8+

Declared floor; 3.11+ still gets security fixes

Apache-2.0

License

Basic Usage

The json6 library provides an API nearly identical to Python's built-in json module.

Parsing JSON6 Strings

import json6 # Parse JSON6 string with comments and trailing commas config_string = """ { // Application settings name: 'my-app', version: '1.0.0', features: [ 'comments', 'trailing commas', ], } """ config = json6.loads(config_string) print(config['name']) # 'my-app' print(config['features']) # ['comments', 'trailing commas']

Converting Python to JSON6

import json6 data = { 'name': 'my-app', 'debug': True, 'ports': [3000, 3001], } # Convert to JSON6 string json6_string = json6.dumps(data, indent=2) print(json6_string) # { # name: "my-app", # debug: true, # ports: [ # 3000, # 3001, # ], # } # Keys are unquoted and strings are double-quoted by default. # For single quotes, pass # quote_style=json6.QuoteStyle.ALWAYS_SINGLE

Drop-in Replacement for json

# Replace this: import json # With this: import json6 as json # Your existing code works with JSON6 features! data = json.loads('{ name: "app", /* comment */ }')

API Reference

json6.loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None, allow_duplicate_keys=True, consume_trailing=True, start=None)

Deserialize a JSON6 string to a Python object. The first group of parameters matches the standard json.loads(); allow_duplicate_keys, consume_trailing and start are JSON6-specific. An invalid document raises ValueError, not json.JSONDecodeError.

import json6 from decimal import Decimal # With custom float parser data = json6.loads( '{ price: 19.99 }', parse_float=Decimal ) print(type(data['price'])) # <class 'decimal.Decimal'>

json6.load(fp, *, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None, allow_duplicate_keys=True, consume_trailing=True, start=None)

Deserialize a JSON6 file-like object to a Python object. Takes the same keyword arguments as loads(), and the file may be opened in text or binary mode.

import json6 with open('config.json6', 'r') as f: config = json6.load(f) print(config)

json6.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, quote_keys=False, trailing_commas=True, allow_duplicate_keys=True, quote_style=QuoteStyle.ALWAYS_DOUBLE)

Serialize a Python object to a JSON6 formatted string. The last four parameters control the JSON6 output shape: keys are left unquoted, multi-line output gets a trailing comma, and string values are double-quoted unless you change quote_style.

import json6 data = {'name': 'test', 'value': 42} # Compact print(json6.dumps(data)) # {name: "test", value: 42} # Pretty-printed print(json6.dumps(data, indent=2)) # { # name: "test", # value: 42, # } # With sorted keys print(json6.dumps(data, sort_keys=True))

json6.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

Serialize a Python object to a JSON6 file.

import json6 data = {'name': 'app', 'version': '1.0'} with open('output.json6', 'w') as f: json6.dump(data, f, indent=2)

Reading JSON6 Files

Basic File Reading

import json6 def load_config(path: str) -> dict: """Load a JSON6 configuration file.""" with open(path, 'r', encoding='utf-8') as f: return json6.load(f) config = load_config('config.json6') print(config)

With Error Handling

import json6 from pathlib import Path def load_config(path: str, defaults: dict = None) -> dict: """Load JSON6 config with defaults and error handling.""" config_path = Path(path) defaults = defaults or {} if not config_path.exists(): print(f"Config not found: {path}, using defaults") return defaults try: with open(config_path, 'r', encoding='utf-8') as f: config = json6.load(f) return {**defaults, **config} except ValueError as e: # json6 raises ValueError on a parse error print(f"Error parsing {path}: {e}") raise config = load_config('config.json6', { 'debug': False, 'port': 3000, })

With Pydantic Validation

import json6 from pydantic import BaseModel from typing import List, Optional class DatabaseConfig(BaseModel): host: str port: int database: str ssl: bool = False class AppConfig(BaseModel): name: str version: str debug: bool = False database: DatabaseConfig def load_validated_config(path: str) -> AppConfig: """Load and validate JSON6 config with Pydantic.""" with open(path, 'r') as f: data = json6.load(f) return AppConfig(**data) config = load_validated_config('config.json6') print(config.database.host) # Fully typed!

Command Line Usage

the json6 package includes a command-line tool that parses and pretty-prints JSON6 files. Note that it prints JSON6 by default - pass --as-json when you want standard JSON out.

Convert JSON6 to JSON

# Convert JSON6 to JSON (quotes keys, drops trailing commas) python -m json6 --as-json config.json6 > config.json # Reformat as JSON6 instead (the default) python -m json6 config.json6 # Or from stdin cat config.json6 | python -m json6 --as-json

Validate JSON6

There is no --check flag. The tool exits non-zero on a parse error, so discarding its output is the validation check:

# Check if file is valid JSON6 python -m json6 config.json6 > /dev/null && echo "Valid JSON6"

Other Flags

-c STR parse an inline string instead of a file --indent N spaces per level (default 4) --quote-keys quote every object key --no-trailing-commas omit the trailing comma in multi-line output --quote-style STYLE always_double | always_single | prefer_double | prefer_single --strict / --no-strict reject or allow control characters in strings -V print the library version

Alternative Libraries

While json6 is the most popular choice, here are other Python JSON6 libraries:

pyjson6

A compiled Cython parser, orders of magnitude faster at reading. Its encoder emits JSON-shaped output - quoted keys, no trailing commas - so it reads JSON6 but does not write it. Recent releases add free-threaded (no-GIL) builds.

pip install pyjson6 import pyjson6 data = pyjson6.loads('{ key: "value" }') # Parse errors raise its own exception class, not ValueError - # the two libraries are not error-compatible

commentjson

Unmaintained - last release 2020, and it pins a version of lark-parser abandoned in 2021. It handles // and # line comments and trailing commas only: block comments, unquoted keys and single-quoted strings all fail. Not a JSON6 parser.

pip install commentjson import commentjson data = commentjson.loads('{ "key": "value" // comment\n }') # This raises ValueError - no block-comment support: # commentjson.loads('{ "key": "value" /* comment */ }')

Recommendation: Use json6 for config-sized files, for portability - it is pure Python with no dependencies - and whenever you need to write JSON6. Switch to pyjson6 when read throughput matters: json6's own README warns it "is SLOW. It can be 1000-6000x slower than the C-optimized JSON module, and is 200x slower (or more) than the pure Python JSON module." For a config file loaded once at startup that is irrelevant; for parsing in a loop it is not.

Common Patterns

Environment-Specific Config

import json6 import os from pathlib import Path def load_env_config() -> dict: """Load config based on environment.""" env = os.getenv('APP_ENV', 'development') config_dir = Path('config') # Load base config with open(config_dir / 'base.json6') as f: config = json6.load(f) # Override with environment-specific config env_config_path = config_dir / f'{env}.json6' if env_config_path.exists(): with open(env_config_path) as f: env_config = json6.load(f) config.update(env_config) return config

Type Hints with TypedDict

import json6 from typing import TypedDict, List class ServerConfig(TypedDict): host: str port: int workers: int class AppConfig(TypedDict): name: str version: str server: ServerConfig features: List[str] def load_config(path: str) -> AppConfig: with open(path) as f: return json6.load(f) # type: ignore config: AppConfig = load_config('config.json6') print(config['server']['port']) # Type checker knows this is int

Ready to Use JSON6 in Python?

Explore more examples or check out other language guides.