# What Is JSON Pointer? — RFC 6901 Paths, ~0 and ~1 Escaping, and #/ Fragments

Canonical: https://commareports.com/glossary/json-pointer
Published: 2026-10-24

> JSON Pointer (RFC 6901) is the slash-separated syntax that names exactly one value in a JSON document: /items/0/name. How it parses, why ~1 means a slash, where it shows up ($ref, JSON Patch) and how it differs from JSONPath.

# JSON Pointer

**JSON Pointer is a string that identifies one value inside a JSON
document — `/items/0/name` — defined in RFC 6901.** It is a list of
reference tokens, each prefixed with `/`, applied from the root one step
at a time: an object member by key, or an array element by index.

```json
{
  "build": { "id": "8f2c", "status": "failed" },
  "checks": [
    { "name": "lint", "ok": true },
    { "name": "e2e", "ok": false, "error": "timeout" }
  ],
  "a/b": 1,
  "m~n": 2,
  "": 3
}
```

| Pointer         | Value               |
| --------------- | ------------------- |
| `""`            | the whole document  |
| `/build/status` | `"failed"`          |
| `/checks/1`     | the `e2e` object    |
| `/checks/1/ok`  | `false`             |
| `/a~1b`         | `1` (key `a/b`)     |
| `/m~0n`         | `2` (key `m~n`)     |
| `/`             | `3` (the empty key) |

## The rules

- **The empty string is the root**, not `/`. A lone `/` means the
  member whose key is the empty string.
- **Every token is a key or an index.** Against an array, the token
  must be `0` or a decimal number without leading zeros — `/checks/01`
  is an error, not the second element.
- **Two escapes, and only two.** `~1` is `/`, `~0` is `~`. Decode `~1`
  before `~0`: the key `~1` is encoded `~01`, and decoding in the wrong
  order turns it into `/`.
- **`-` is the slot after the last element.** It never resolves to a
  value; JSON Patch uses it to append.
- **No wildcards, filters or ranges.** One pointer, at most one value.
  A pointer to a key that isn't there fails rather than returning empty.

## Two spellings

The plain form above is what JSON Patch and most APIs use. The **URI
fragment** form prefixes `#` and percent-encodes anything not allowed
in a URI fragment:

```text
/build/status          plain
#/build/status         fragment
#/paths/~1users~1{id}  OpenAPI path "/users/{id}" — slashes escaped
#/a%20b                key "a b"
```

That is why JSON Schema and OpenAPI references look like
`"$ref": "#/$defs/address"` or `"#/components/schemas/User"` — the part
after `#` is a JSON Pointer into the current document.

## Where you meet it

- **JSON Patch (RFC 6902)** — every `path` and `from` is a pointer:
  `{ "op": "replace", "path": "/build/status", "value": "passed" }`.
  See [JSON Patch](/glossary/json-patch).
- **JSON Merge Patch** doesn't use it; it sends a partial document
  instead.
- **JSON Schema and OpenAPI** — `$ref` fragments, and validators report
  the failing location as an instance pointer such as `/checks/1/ok`.
- **Problem Details and API error bodies** often name the bad field with
  a pointer (`"pointer": "/data/attributes/email"` in JSON:API).
- **Libraries** — `jsonpointer` (Python), `json-pointer` (npm),
  `nlohmann::json_pointer` (C++), Jackson's `JsonNode.at()` (Java).

## JSON Pointer, JSONPath and jq

|           | JSON Pointer      | [JSONPath](/glossary/jsonpath) | jq                     |
| --------- | ----------------- | ------------------------------ | ---------------------- |
| Spec      | RFC 6901          | RFC 9535                       | the jq manual          |
| Root      | `""`              | `$`                            | `.`                    |
| Example   | `/checks/1/error` | `$.checks[1].error`            | `.checks[1].error`     |
| Returns   | one value         | a list of matches              | a stream               |
| Wildcards | no                | `[*]`, `..`                    | `.[]`, `..`            |
| Filters   | no                | `?(@.ok == false)`             | `select(.ok == false)` |
| Used to   | address           | query                          | query and transform    |

Rule of thumb: if something has to be _changed_ or _referenced_ at a
single location, it is a pointer. If you are _looking for_ values, it is
JSONPath or jq.

## Getting a pointer without counting brackets

Comma's free [JSON viewer](/tools/json-viewer) folds a document into a
tree and copies the path to any node in one click, and the
[JSON diff](/tools/json-diff) lists every change between two documents
by path with an RFC 6902 patch you can apply. Both run in your browser,
and either can be published as a link reviewers comment on, node by
node.

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited
revision history.

**[Open the JSON viewer →](/tools/json-viewer)**

### Related

- [JSON Patch](/glossary/json-patch) · [JSONPath](/glossary/jsonpath) · [JSON Schema](/glossary/json-schema)
- [JSON diff](/tools/json-diff) · [JSON viewer](/tools/json-viewer) · [JSON formatter](/tools/json-formatter)
- [Glossary](/glossary)
