Skip to main content
CuteJSON
↑↓ Navigate Enter Select Esc Close

JSON Pointer vs JSONPath: what is the difference

Published 3 min read By Akash Kinkar Pandey

Both JSON Pointer and JSONPath address locations inside a JSON document, and both show up in the same kinds of tools: $ref in JSON Schema, PATCH operations, path-based diffing. They solve different problems, and knowing which one a given task actually calls for saves picking the wrong tool for it.

JSON Pointer: one location, RFC 6901

A pointer is a sequence of / separated tokens: /user/name means the name key inside the user object, /items/0 means the first element of the items array. Two characters need escaping inside a token (~1 for a literal /, ~0 for a literal ~), and the empty string as a pointer means the whole document. That is the entire grammar. A pointer resolves to exactly one value, or fails, with nothing in between: there is no wildcard, no filter, no way to match more than the one location it names.

{ "user": { "name": "Ada", "roles": ["admin", "editor"] } }

/user/name resolves to "Ada". /user/roles/1 resolves to "editor". /user/email fails, because that key does not exist. Nothing in the pointer syntax can ask for “every role” in one expression; the caller already has to know the index.

JSONPath: a query language

JSONPath, standardized as RFC 9535, is built for matching, not just addressing. $.user.roles[*] returns both roles in the example above in one query. $..email searches every level of the document for any key named email, however deep it is nested. Filter expressions like $.items[?(@.price > 100)] select array elements by a condition on their own content. A JSONPath query can return zero matches, one, or many, which is a fundamentally different contract from a pointer’s resolve-or-fail.

The practical difference

A pointer names a location you already know. A JSONPath query describes a condition and lets the engine find what satisfies it. That difference decides which one fits a given job:

  • You already know exactly which value you want (“the third element of the shipping address array”): use a pointer. It is simpler, has one unambiguous meaning per document, and every implementation agrees on what it does, since the RFC leaves little room for dialect differences.
  • You are searching for values that match a condition, or you do not know the exact path in advance (“every object with a status of failed, wherever it appears”): reach for JSONPath. This is also where dialect differences start to matter: JSONPath implementations vary more than RFC 9535’s own examples suggest, so a query written for one library is not guaranteed to behave identically in another.

Where each shows up in practice

JSON Patch (RFC 6902) operations use pointers exclusively; every "path" in an add, remove, replace or move operation is a JSON Pointer, because a patch operation targets one exact location by design. JSON Schema’s $ref keyword also resolves via pointer syntax, for the same reason: a schema reference points at one definition, not a set of them. JSONPath shows up wherever a person or a tool needs to query a document interactively: debugging a large API response, extracting a field from logs, or building a rule that should match any document with a given shape regardless of exactly where the relevant field sits.

Trying both

The JSON Pointer Evaluator resolves a pointer against a document and, on a failed lookup, reports how far it got and what keys actually exist at that point, rather than a bare “not found.” The JSONPath Tester runs the documented subset of RFC 9535 with function extensions, and the JSONPath cheat sheet on this site’s own blog has a worked example for every selector worth knowing. How to use JSON Pointer covers the pointer syntax itself in more depth, escapes included.

Back to all posts