# canonical-json

> a canonical json implementation

Latest version **0.4.0** (published 2026-03-24) · MIT license · 0 weekly downloads

## Install

```sh
npm install canonical-json
pnpm add canonical-json
yarn add canonical-json
bun add canonical-json
```

Provides the command `canonical-json`.

## Health

**Score 60/100 (C)** — status: active.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.4.0 |
| Published | 2026-03-24 |
| First published | 2013-01-29 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=14 |
| Dependencies | 0 |
| Unpacked size | 13.5 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 44 |
| Author | Mirko Kiefer |
| Maintainers | mirkok |
| Keywords | json, canonical, deterministic, stringify, sorted, stable |

## Links

- npm: https://www.npmjs.com/package/canonical-json
- Repository: https://github.com/mirkokiefer/canonical-json
- Issues: https://github.com/mirkokiefer/canonical-json/issues
- npm.io page: https://npm.io/package/canonical-json

## Alternatives

- [@mapbox/jsonlint-lines-primitives](https://npm.io/package/@mapbox/jsonlint-lines-primitives.md) — 5.3M weekly downloads
- [reftools](https://npm.io/package/reftools.md) — 3.5M weekly downloads
- [@hey-api/openapi-ts](https://npm.io/package/@hey-api/openapi-ts.md) — 3.5M weekly downloads
- [@mapbox/geojson-rewind](https://npm.io/package/@mapbox/geojson-rewind.md) — 2.4M weekly downloads
- [turbo-stream](https://npm.io/package/turbo-stream.md) — 1.7M weekly downloads

## Recent versions

- 0.4.0 (latest) — 2026-03-24
- 0.2.0 — 2025-05-01
- 0.1.0 — 2025-05-01
- 0.0.4 — 2014-02-06
- 0.0.3 — 2013-06-07
- 0.0.1 — 2013-01-29

## README

[![npm version](https://img.shields.io/npm/v/canonical-json.svg)](https://www.npmjs.com/package/canonical-json)
[![tests](https://github.com/mirkokiefer/canonical-json/actions/workflows/test.yml/badge.svg)](https://github.com/mirkokiefer/canonical-json/actions)

# canonical-json - Deterministic JSON.stringify()

A drop-in replacement for `JSON.stringify` that produces **deterministic**, **canonical JSON** output compliant with [RFC 8785 (JSON Canonicalization Scheme)](https://www.rfc-editor.org/rfc/rfc8785).

Ideal for content-addressable hashing, digital signatures, and distributed systems where identical objects must produce identical bytes.

## Install

```bash
npm install canonical-json
```

## Usage

```js
import stringify from 'canonical-json'

stringify({ b: 2, a: 1, c: { y: 0, x: 9 } })
// '{"a":1,"b":2,"c":{"x":9,"y":0}}'
```

### Replacer

Supports both function and array replacers, just like `JSON.stringify`:

```js
stringify({ a: 1, b: 2, c: 3 }, ['a', 'c'])
// '{"a":1,"c":3}'

stringify({ a: 1, b: 2 }, (key, value) => key === 'b' ? undefined : value)
// '{"a":1}'
```

### Indentation

```js
stringify({ a: 1 }, null, 2)
// '{\n  "a": 1\n}'
```

### Custom Key Order

Pass a comparator function as the fourth argument:

```js
const order = { first: 1, second: 2, third: 3 }
const cmp = (a, b) => (order[a] || 9999) - (order[b] || 9999)

stringify({ third: 'c', first: 'a', second: 'b' }, null, null, cmp)
// '{"first":"a","second":"b","third":"c"}'
```

### Streaming with `walk`

`walk` traverses the value and streams canonical JSON chunks to a callback — without building the full string:

```js
import { createHash } from 'node:crypto'
import { walk } from 'canonical-json'

const hasher = createHash('sha256')
walk(obj, chunk => hasher.update(chunk))
const digest = hasher.digest('hex')
```

### Convenience hashing

For Node.js/Bun/Deno, a separate entry point provides one-liner hashing without pulling `node:crypto` into browser builds:

```js
import { hash } from 'canonical-json/hash'

hash(obj)              // sha256 hex digest
hash(obj, 'md5')       // md5 hex digest
hash(obj, 'sha512')    // sha512 hex digest
```

## API

```ts
// canonical-json
export default function stringify(
  value: any,
  replacer?: ((key: string, value: any) => any) | string[],
  space?: string | number,
  keyCompare?: (a: string, b: string) => number
): string | undefined

export function walk(
  value: any,
  write: (chunk: string) => void,
  keyCompare?: (a: string, b: string) => number
): void

// canonical-json/hash (Node.js/Bun/Deno only)
export function hash(
  value: any,
  algorithm?: string,    // default: 'sha256'
  keyCompare?: (a: string, b: string) => number
): string               // hex digest
```

## RFC 8785 Compliance

When called without `replacer`, `space`, or `keyCompare`, the output conforms to [RFC 8785 (JCS)](https://www.rfc-editor.org/rfc/rfc8785):

- Object keys sorted by UTF-16 code unit order
- Numbers serialized per ES6 `Number.toString()` rules (`-0` becomes `0`)
- Only mandatory characters escaped (`U+0000`-`U+001F`, `"`, `\`)
- No whitespace

## CLI

```bash
# Canonicalize
echo '{"b":2,"a":1}' | canonical-json
# {"a":1,"b":2}

# Content hash (default sha256)
echo '{"b":2,"a":1}' | canonical-json hash
# 43258cff783fe7036d8a43033f830adfc60ec037...

# Hash with specific algorithm
echo '{"b":2,"a":1}' | canonical-json hash --algo md5

# Hash multiple files
canonical-json hash *.json

# Verify files are canonical (exit 1 if not)
canonical-json verify data.json
canonical-json verify *.json
```

## Test

```bash
npm test
```

Zero dependencies. Tests use Node's built-in test runner.

## License

MIT

---
_Source: https://npm.io/package/canonical-json · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
