{"id":30456414,"url":"https://github.com/micahkepe/jsongrep","last_synced_at":"2026-04-02T19:33:04.829Z","repository":{"id":308962890,"uuid":"1034729507","full_name":"micahkepe/jsongrep","owner":"micahkepe","description":"A path query language for JSON, YAML, TOML, and other serialization formats.","archived":false,"fork":false,"pushed_at":"2026-03-31T04:30:05.000Z","size":61811,"stargazers_count":503,"open_issues_count":4,"forks_count":9,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-31T05:56:05.572Z","etag":null,"topics":["cbor","command-line-tool","developer-tools","json","messagepack","query-language","search","toml","yaml"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/jsongrep","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/micahkepe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"micahkepe"}},"created_at":"2025-08-08T22:08:52.000Z","updated_at":"2026-03-31T04:30:08.000Z","dependencies_parsed_at":"2025-08-09T20:30:30.868Z","dependency_job_id":null,"html_url":"https://github.com/micahkepe/jsongrep","commit_stats":null,"previous_names":["micahkepe/rq","micahkepe/jsongrep"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/micahkepe/jsongrep","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahkepe%2Fjsongrep","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahkepe%2Fjsongrep/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahkepe%2Fjsongrep/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahkepe%2Fjsongrep/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/micahkepe","download_url":"https://codeload.github.com/micahkepe/jsongrep/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micahkepe%2Fjsongrep/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31314379,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cbor","command-line-tool","developer-tools","json","messagepack","query-language","search","toml","yaml"],"created_at":"2025-08-23T16:32:48.794Z","updated_at":"2026-04-02T19:33:04.823Z","avatar_url":"https://github.com/micahkepe.png","language":"Rust","readme":"\u003cdiv align=\"center\"\u003e\n \u003cimg src=\"./images/logo.svg\" alt=\"jsongrep SVG logo\"/\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://crates.io/crates/jsongrep\"\u003e\u003cimg alt=\"Crates.io Version\" src=\"https://img.shields.io/crates/v/jsongrep\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/micahkepe/jsongrep/blob/main/LICENSE\"\u003e\u003cimg alt=\"GitHub License\" src=\"https://img.shields.io/github/license/micahkepe/jsongrep\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/micahkepe/jsongrep/actions\"\u003e\u003cimg alt=\"GitHub Actions Workflow Status\" src=\"https://img.shields.io/github/actions/workflow/status/micahkepe/jsongrep/rust.yml\"\u003e \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ccode\u003ejsongrep\u003c/code\u003e is a command-line tool and Rust library for\n\u003ca href=\"https://micahkepe.com/jsongrep/end_to_end_xlarge/report/index.html\"\u003efast querying\u003c/a\u003e\nof JSON, YAML, TOML, JSONL, CBOR, and MessagePack documents using \u003cstrong\u003eregular path expressions\u003c/strong\u003e.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./images/screenshot.png\" alt=\"jsongrep colored output example\" width=\"700\"/\u003e\n\u003c/p\u003e\n\n## Quick Links\n\n- [Installation](#installation)\n- [Quick Example](#quick-example)\n- [Why jsongrep?](#why-jsongrep)\n  - [jsongrep vs jq](#jsongrep-vs-jq)\n- [Benchmarks](#benchmarks)\n- [Multi\\-Format Input](#multi-format-input)\n- [CLI Usage](#cli-usage)\n  - [More CLI Examples](#more-cli-examples)\n- [Query Syntax](#query-syntax)\n- [Library Usage](#library-usage)\n- [Shell Completions](#shell-completions)\n- [Man Pages](#man-pages)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Installation\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://repology.org/project/jsongrep/versions\"\u003e\n    \u003cimg src=\"https://repology.org/badge/vertical-allrepos/jsongrep.svg\" alt=\"Packaging status\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n**via Homebrew**:\n\n```bash\nbrew install jsongrep\n```\n\n**via Winget**:\n\n```bash\nwinget install jsongrep\n```\n\n**via Scoop**:\n\n```bash\nscoop install jsongrep\n```\n\n**via `cargo`**:\n\n```bash\ncargo install jsongrep\n```\n\n## Quick Example\n\n```bash\n# Extract all firstnames from the Nobel Prize API\n$ curl -s https://api.nobelprize.org/v1/prize.json | jg 'prizes[0].laureates[*].firstname'\nprizes.[0].laureates.[0].firstname:\n\"Susumu\"\nprizes.[0].laureates.[1].firstname:\n\"Richard\"\nprizes.[0].laureates.[2].firstname:\n\"Omar M.\"\n\n# Works with inline JSON too\n$ echo '{\"users\": [{\"name\": \"Alice\"}, {\"name\": \"Bob\"}]}' | jg 'users.[*].name'\nusers.[0].name:\n\"Alice\"\nusers.[1].name:\n\"Bob\"\n```\n\n## Why jsongrep?\n\nJSON documents are trees: objects and arrays branch into nested values, with\nedges labeled by field names or array indices. `jsongrep` lets you describe\n**sets of paths** through this tree using regular expression operators - the\nsame way you'd match patterns in text.\n\n```\n**.name          # Kleene star: match \"name\" under nested objects\nusers[*].email   # Wildcard: all emails in the users array\n(error|warn).*   # Disjunction: any field under \"error\" or \"warn\"\n(* | [*])*.name  # Any depth: match \"name\" through both objects and arrays\n```\n\nThis is different from tools like `jq`, which use a filter pipeline to transform\ndata. With `jsongrep`, you declare _what paths to match_ rather than describing\n_how to transform_. The query compiles to a\n[DFA](https://en.wikipedia.org/wiki/Deterministic_finite_automaton) that\nprocesses the document efficiently.\n\nSee the [blog post](https://micahkepe.com/blog/jsongrep/) for the motivation\nand design behind jsongrep.\n\n### jsongrep vs jq\n\n`jq` is a powerful tool, but its filter syntax can be verbose for common\npath-matching tasks. `jsongrep` is declarative: you describe the shape of the\npaths you want, and the engine finds them.\n\n**Find a field at any depth:**\n\n```bash\n# jsongrep: -F treats the query as a literal field name at any depth\n$ curl -s https://api.nobelprize.org/v1/prize.json | jg -F firstname | head -6\nprizes.[0].laureates.[0].firstname:\n\"Susumu\"\nprizes.[0].laureates.[1].firstname:\n\"Richard\"\nprizes.[0].laureates.[2].firstname:\n\"Omar M.\"\n\n# jq: requires a recursive descent operator and null suppression\n$ curl -s https://api.nobelprize.org/v1/prize.json | jq '.. | .firstname? // empty' | head -3\n\"Susumu\"\n\"Richard\"\n\"Omar M.\"\n```\n\n`jsongrep` also shows _where_ each match was found (e.g.,\n`prizes.[0].laureates.[0].firstname:`), which `jq` does not. _(Examples below\nshow terminal output; when piped, path headers are hidden by default. See\n`--with-path` / `--no-path`.)_\n\n**Select multiple fields at once:**\n\n```bash\n# jsongrep: disjunction with (year|category)\n$ curl -s https://api.nobelprize.org/v1/prize.json | jg 'prizes[0].(year|category)'\nprizes.[0].year:\n\"2025\"\nprizes.[0].category:\n\"chemistry\"\n\n# jq: requires listing each field separately\n$ curl -s https://api.nobelprize.org/v1/prize.json | jq '.prizes[0] | .year, .category'\n\"2025\"\n\"chemistry\"\n```\n\n**Count matches:**\n\n```bash\n# jsongrep\n$ curl -s https://api.nobelprize.org/v1/prize.json | jg -F firstname --count -n\nFound matches: 1026\n\n# jq\n$ curl -s https://api.nobelprize.org/v1/prize.json | jq '[.. | .firstname? // empty] | length'\n1026\n```\n\n**Pretty-print JSON** (like `jq '.'`):\n\n```bash\n$ echo '{\"name\":\"Ada\",\"age\":36}' | jg ''\n{\n  \"name\": \"Ada\",\n  \"age\": 36\n}\n```\n\n## Benchmarks\n\n`jsongrep` is benchmarked against\n[jsonpath-rust](https://crates.io/crates/jsonpath-rust),\n[jmespath](https://crates.io/crates/jmespath),\n[jaq](https://crates.io/crates/jaq-core), and\n[jql](https://crates.io/crates/jql-runner) using\n[Criterion](https://crates.io/crates/criterion). Four benchmark groups isolate\ndifferent costs:\n\n| Group            | What's measured                                   |\n| ---------------- | ------------------------------------------------- |\n| `document_parse` | JSON string \u0026rarr; in-memory document             |\n| `query_compile`  | Query string \u0026rarr; compiled query/DFA/filter     |\n| `query_search`   | Search only (pre-parsed doc + pre-compiled query) |\n| `end_to_end`     | Full pipeline: parse + compile + search           |\n\nTest data ranges from a small sample JSON to a 190 MB GeoJSON file\n([citylots.json](https://github.com/zemirco/sf-city-lots-json)), with queries\nchosen to exercise equivalent functionality across tools (recursive descent,\nwildcards, nested paths). Where a tool lacks a feature, the benchmark is\nskipped rather than faked.\n\n**End-to-end on 190 MB GeoJSON (xlarge):**\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./images/benchmark-xlarge-e2e.png\" alt=\"End-to-end xlarge benchmark violin plot\" width=\"700\"/\u003e\n\u003c/p\u003e\n\n[Interactive Criterion reports](https://micahkepe.com/jsongrep/report/index.html)\n\u0026nbsp;|\u0026nbsp; [Benchmark source and methodology](./benches/README.md)\n\n## Multi-Format Input\n\n`jg` natively supports multiple serialization formats. Non-JSON formats are\nconverted to JSON at the boundary, then queried with the same engine, so your\nqueries work identically regardless of input format.\n\n**Query your Cargo.toml:**\n\n```bash\n$ jg 'dependencies.*.version' Cargo.toml\ndependencies.clap.version:\n\"4.5.43\"\ndependencies.serde.version:\n\"1.0.219\"\n...\n```\n\n**Query a docker-compose.yml:**\n\n```bash\n$ jg 'services.*.image' docker-compose.yml\nservices.web.image:\n\"nginx:latest\"\nservices.db.image:\n\"postgres:16\"\n```\n\n**JSONL/NDJSON**: each line becomes an array element:\n\n```bash\n$ jg '[*].email' users.jsonl\n[0].email:\n\"alice@example.com\"\n[1].email:\n\"bob@example.com\"\n```\n\n**Explicit format flag** (useful for stdin or non-standard extensions):\n\n```bash\n$ cat config.yaml | jg -f yaml 'database.host'\ndatabase.host:\n\"localhost\"\n```\n\n**Binary formats** (CBOR, MessagePack):\n\n```bash\n$ jg 'name' data.cbor\n$ jg -f msgpack 'name' data.bin\n```\n\n| Format       | Extensions          | Feature flag | Notes                   |\n| ------------ | ------------------- | ------------ | ----------------------- |\n| JSON         | `.json` (default)   | —            | Always available        |\n| JSONL/NDJSON | `.jsonl`, `.ndjson` | —            | Wrapped into JSON array |\n| YAML         | `.yaml`, `.yml`     | `yaml`       | Included by default     |\n| TOML         | `.toml`             | `toml`       | Included by default     |\n| CBOR         | `.cbor`             | `cbor`       | Included by default     |\n| MessagePack  | `.msgpack`, `.mp`   | `msgpack`    | Included by default     |\n\nAll format dependencies are included by default. To build without them:\n\n```bash\ncargo install jsongrep --no-default-features\n```\n\n## CLI Usage\n\n```\nJSONPath-inspired query language for JSON, YAML, TOML, and other serialization formats\n\nUsage: jg [OPTIONS] [QUERY] [FILE] [COMMAND]\n\nCommands:\n  generate  Generate additional documentation and/or completions\n\nArguments:\n  [QUERY]  Query string (e.g., \"**.name\")\n  [FILE]   Optional path to file. If omitted, reads from STDIN\n\nOptions:\n  -i, --ignore-case      Case insensitive search\n      --compact          Do not pretty-print the JSON output\n      --count            Display count of number of matches\n      --depth            Display depth of the input document\n  -n, --no-display       Do not display matched JSON values\n  -F, --fixed-string     Treat the query as a literal field name and search at any depth\n      --with-path        Always print the path header, even when output is piped\n      --no-path          Never print the path header, even in a terminal\n  -f, --format \u003cFORMAT\u003e  Input format (auto-detects from file extension if omitted) [default: auto] [possible values: auto, json, jsonl, yaml, toml, cbor, msgpack]\n  -h, --help             Print help (see more with '--help')\n  -V, --version          Print version\n```\n\n### More CLI Examples\n\n**Search for a literal field name at any depth:**\n\n```bash\ncurl -s https://api.nobelprize.org/v1/prize.json | jg -F motivation | head -4\n```\n\n**Count matches without displaying them:**\n\n```bash\ncurl -s https://api.nobelprize.org/v1/prize.json | jg -F firstname --count -n\n# Found matches: 1026\n```\n\n**Piping to other tools:**\n\nBy default, path headers display in terminals and hide when output is piped\n(like ripgrep's `--heading`). This makes piping to `sort`, `uniq`, etc., work\ncleanly:\n\n```bash\n# Piped: values only, ready for sort/uniq/wc\n$ curl -s https://api.nobelprize.org/v1/prize.json | jg -F firstname | sort | head -3\n\"A. Michael\"\n\"Aage N.\"\n\"Aaron\"\n\n# Force path headers when piped\n$ curl -s https://api.nobelprize.org/v1/prize.json | jg -F firstname --with-path | head -4\nprizes.[0].laureates.[0].firstname:\n\"Susumu\"\nprizes.[0].laureates.[1].firstname:\n\"Richard\"\n```\n\n## Query Syntax\n\nQueries are **regular expressions over paths**. If you know regex, this will\nfeel familiar:\n\n| Operator     | Example              | Description                                                   |\n| ------------ | -------------------- | ------------------------------------------------------------- |\n| Sequence     | `foo.bar.baz`        | **Concatenation**: match path `foo` \u0026rarr; `bar` \u0026rarr; `baz` |\n| Disjunction  | `foo \\| bar`         | **Union**: match either `foo` or `bar`                        |\n| Kleene star  | `**`                 | Match zero or more field accesses                             |\n| Repetition   | `foo*`               | Repeat the preceding step zero or more times                  |\n| Wildcards    | `*` or `[*]`         | Match any single field or array index                         |\n| Optional     | `foo?.bar`           | Optional `foo` field access                                   |\n| Field access | `foo` or `\"foo bar\"` | Match a specific field (quote if spaces)                      |\n| Array index  | `[0]` or `[1:3]`     | Match specific index or slice (exclusive end)                 |\n\nThese queries can be arbitrarily nested with parentheses. For example,\n`foo.(bar|baz).qux` matches `foo.bar.qux` or `foo.baz.qux`.\n\nThis also means that you can recursively descend **any** path with `(* | [*])*`,\ne.g., `(* | [*])*.foo` to find all paths matching `foo` field at any\ndepth.\n\nThe query engine compiles expressions to an\n[NFA](https://en.wikipedia.org/wiki/Nondeterministic_finite_automaton), then\ndeterminizes to a\n[DFA](https://en.wikipedia.org/wiki/Deterministic_finite_automaton) for\nexecution. See the [grammar](./src/query/grammar) directory and the\n[`query`](./src/query) module for implementation details.\n\n\u003e **Experimental:** The grammar supports `/regex/` syntax for matching field\n\u003e names by pattern, but this is not yet fully implemented. Determinizing\n\u003e overlapping regexes (e.g., `/a/` vs `/aab/`) requires subset construction\n\u003e across multiple patterns - planned but not complete.\n\n## Library Usage\n\nAdd to your `Cargo.toml`:\n\n```toml\n[dependencies]\njsongrep = \"0.8.1\"\n```\n\nParse a query string, build a DFA, and search:\n\n```rust\nuse jsongrep::{Value, query::{DFAQueryEngine, QueryDFA}};\n\nlet json: Value = serde_json::from_str(r#\"{\"users\": [{\"name\": \"Alice\"}]}\"#)?;\n\nlet dfa = QueryDFA::from_query_str(\"users[*].name\")?;\nlet results = DFAQueryEngine::find_with_dfa(\u0026json, \u0026dfa);\n\nfor result in \u0026results {\n    println!(\"{:?}: {}\", result.path, result.value);\n}\n```\n\nBuild queries programmatically with `QueryBuilder`:\n\n```rust\nuse jsongrep::query::QueryBuilder;\n\nlet query = QueryBuilder::new()\n    .field(\"users\")\n    .array_wildcard()\n    .field(\"name\")\n    .build();\n```\n\nMore examples in the [examples](./examples) directory.\n\n## Shell Completions\n\n\u003e [!NOTE]\n\u003e Installed automatically with most package managers.\n\nGenerate completions with `jg generate shell \u003cSHELL\u003e`:\n\n```bash\n# Bash\njg generate shell bash \u003e /etc/bash_completion.d/jg.bash\n\n# Zsh\njg generate shell zsh \u003e ~/.zsh/completions/_jg\n\n# Fish\njg generate shell fish \u003e ~/.config/fish/completions/jg.fish\n```\n\n## Man Pages\n\n\u003e [!NOTE]\n\u003e Installed automatically with most package managers.\n\n```bash\njg generate man -o ~/.local/share/man/man1/\nman jg\n```\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nMIT - see [LICENSE.md](LICENSE.md).\n","funding_links":["https://github.com/sponsors/micahkepe"],"categories":["Applications"],"sub_categories":["Text processing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicahkepe%2Fjsongrep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicahkepe%2Fjsongrep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicahkepe%2Fjsongrep/lists"}