How to Install tree-sitter-cli on Ubuntu: Generate, Test and Run Tree-sitter Parsers
Tree-sitter generates parsers and keeps their syntax trees up to date as a file changes, fast enough to run on every keystroke. That is what powers syntax highlighting, folding and structural selection in Neovim, Helix, Zed and a growing list of other tools. The Tree-sitter CLI is how you work with those parsers directly: it creates grammar projects, generates and compiles parsers, runs their test suites, and parses, queries and highlights files from your shell.
Ubuntu’s archive is not much help here. Jammy has no tree-sitter-cli package, Noble is stuck on 0.20.8, and even Resolute trails upstream by several releases. Upstream’s prebuilt Linux binary requires glibc 2.39, so it will not start on Jammy, and the alternatives, cargo install or a global npm package, mean carrying a toolchain around and tracking updates yourself.
The unofficial deb.griffo.io repository offers a cleaner path: the latest Tree-sitter CLI packaged as a proper Ubuntu .deb and delivered over APT, so you install it and keep it current with the same commands you already use.
Install the Latest tree-sitter-cli on Ubuntu: The Short Version
If you only came for the commands, this adds the repository and installs the latest tree-sitter-cli .deb package on Ubuntu:
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://deb.griffo.io/EA0F721D231FDD3A0A17B9AC7808B4DD62C41256.asc | sudo gpg --dearmor --yes -o /etc/apt/keyrings/deb.griffo.io.gpg
echo "deb [signed-by=/etc/apt/keyrings/deb.griffo.io.gpg] https://deb.griffo.io/apt $(lsb_release -sc 2>/dev/null) main" | sudo tee /etc/apt/sources.list.d/deb.griffo.io.list > /dev/null
sudo apt update
sudo apt install tree-sitter-cli
The rest of this guide explains what each command does, how to verify the install, how to keep the CLI up to date, and what to check when something goes wrong.
What Makes the Tree-sitter CLI Special?
- 🌳 Grammar to parser in one step -
tree-sitter generatecompiles agrammar.jsinto a portable C parser with no runtime dependencies. - 🧪 Corpus testing - Write inputs alongside their expected syntax trees and let
tree-sitter testcatch regressions. - 🔍 Terminal-first exploration - Query, highlight and tag real source files without writing a line of host code.
- 🏗️ Ready-made project layout -
tree-sitter initsets up a grammar repository with bindings for C, Rust, Node.js, Python, Go, Swift and more. - 🧩 Native or Wasm output - Produce a shared library with
tree-sitter build, or a.wasmmodule with--wasm. - 🕹️ Interactive playground -
tree-sitter playgroundserves a browser UI for poking at your grammar’s trees and queries. - ⚙️ Works without Node.js - A QuickJS engine is built in and evaluates grammars via
--js-runtime native. - 🐛 Serious debugging aids - Parse logs, graphical
log.htmltraces, conflict reports and a fuzzer for hard cases.
Why Use the deb.griffo.io Repository?
- Easy installation and updates through APT rather than
cargoornpm. - Far newer than the Ubuntu archive, and available on Jammy, which has no package at all.
- One binary that runs everywhere: it is built from the upstream release tag against Jammy’s glibc, so every supported release can run it.
- Completions out of the box for bash, fish, zsh and nushell.
- Always tracks upstream releases so you stay near the latest Tree-sitter.
- Works across supported Ubuntu releases on amd64, arm64, armhf and i386, with the codename detected for you.
Prerequisites
Before starting, confirm you have:
- An Ubuntu system (Jammy 22.04 LTS, Noble 24.04 LTS, Questing 25.10, or Resolute 26.04 LTS)
- An amd64, arm64, armhf or i386 machine
sudoprivilegescurlinstalled (sudo apt install curlif needed)
The package needs nothing beyond the C library, but a couple of commands rely on tools you install separately:
- A C compiler for building and testing parsers:
sudo apt install build-essential - Node.js for
tree-sitter generate, unless you switch it to the embedded runtime with--js-runtime native
Step 1: Add the deb.griffo.io Repository
Register the key and repository source:
# Create the keyrings directory
sudo install -d -m 0755 /etc/apt/keyrings
# Download and install the repository GPG key
curl -fsSL https://deb.griffo.io/EA0F721D231FDD3A0A17B9AC7808B4DD62C41256.asc | sudo gpg --dearmor --yes -o /etc/apt/keyrings/deb.griffo.io.gpg
# Add the repository (auto-detects your distro codename)
echo "deb [signed-by=/etc/apt/keyrings/deb.griffo.io.gpg] https://deb.griffo.io/apt $(lsb_release -sc 2>/dev/null) main" | sudo tee /etc/apt/sources.list.d/deb.griffo.io.list > /dev/null
# Update the package list
sudo apt update
Breaking it down:
- Create the keyrings directory - makes sure
/etc/apt/keyringsexists with the right permissions. - Install the GPG key - downloads and de-armours the repository key into its own keyring so APT can verify signatures.
- Add the repository - writes a
signed-bysource line, lettinglsb_release -scfill in your Ubuntu codename. - Update the package list - refreshes APT’s view of available packages.
Step 2: Update the Package List
If you did not run the final command above, do it now:
sudo apt update
From Noble onwards, Ubuntu’s universe component has its own, older tree-sitter-cli. Make sure APT prefers the deb.griffo.io build:
apt policy tree-sitter-cli
The candidate version should end in your codename, such as 0.27.0-1~noble, and come from https://deb.griffo.io/apt.
Step 3: Install tree-sitter-cli
Install with APT. Adding build-essential now saves a trip later if you intend to compile parsers:
sudo apt install tree-sitter-cli build-essential
APT fetches the CLI and installs it across the system, shell completions included.
Step 4: Verify the Installation
Keep in mind that you install tree-sitter-cli, but you run tree-sitter. Check the version:
tree-sitter --version
You should see something like:
tree-sitter 0.27.0
There is no man page upstream; run tree-sitter --help for the full command listing, or tree-sitter parse --help for a single subcommand.
Getting Started with the Tree-sitter CLI
Scaffolding a Grammar Project
Each language gets its own repository, named tree-sitter-<language> by convention. Start in an empty folder:
mkdir tree-sitter-kv && cd tree-sitter-kv
tree-sitter init
The CLI prompts for the language name, file extensions, author and licence, then creates tree-sitter.json, a starter grammar.js and the language bindings. After upgrading the CLI, tree-sitter init --update brings those generated files up to date.
Next, write the grammar. Here is a complete one for a small key = value settings format:
module.exports = grammar({
name: 'kv',
extras: $ => [/\s/, $.comment],
rules: {
document: $ => repeat($.pair),
pair: $ => seq(field('key', $.key), '=', field('value', $.value)),
key: _ => /[a-zA-Z_][a-zA-Z0-9_]*/,
value: $ => choice($.number, $.string),
number: _ => /\d+/,
string: _ => /"[^"]*"/,
comment: _ => token(seq('#', /.*/)),
},
});
Generating a Parser
Generation produces src/parser.c along with src/grammar.json and src/node-types.json:
# Evaluate grammar.js with node
tree-sitter generate
# Or skip Node.js entirely with the built-in QuickJS engine
tree-sitter generate --js-runtime native
Export TREE_SITTER_JS_RUNTIME=native in your shell profile to make QuickJS the default.
Testing the Grammar
Corpus tests are text files in test/corpus/. A test is a title, some input and the tree it should parse to:
==================
Simple pairs
==================
name = "tree-sitter"
port = 8080
---
(document
(pair
key: (key)
value: (value
(string)))
(pair
key: (key)
value: (value
(number))))
Then run them:
# Build the parser if it changed and run the full corpus
tree-sitter test
# Limit the run to tests matching a regex
tree-sitter test --include "pairs"
# Overwrite expected trees with what the parser produces now
tree-sitter test --update
The parser is compiled with your system C compiler before the tests run, so build-essential needs to be installed.
Parsing Real Input
Given a sample file, tree-sitter parse prints the syntax tree with the position of every node:
tree-sitter parse example.kv
(document [0, 0] - [3, 0]
(comment [0, 0] - [0, 6])
(pair [1, 0] - [1, 20]
key: (key [1, 0] - [1, 4])
value: (value [1, 7] - [1, 20]
(string [1, 7] - [1, 20])))
(pair [2, 0] - [2, 11]
key: (key [2, 0] - [2, 4])
value: (value [2, 7] - [2, 11]
(number [2, 7] - [2, 11]))))
Useful variations:
# Show every node, anonymous tokens included, in a readable layout
tree-sitter parse --cst example.kv
# Suppress trees and print per-file statistics for a whole folder
tree-sitter parse --quiet --stat samples/*.kv
# Produce log.html with a graph of each parser step
tree-sitter parse --debug-graph example.kv
Input with syntax errors produces ERROR or MISSING nodes and an exit status of 1, so the same command doubles as a quick check of a grammar against a directory of real files.
Queries, Highlighting and Tags
Queries match patterns in the tree and label the interesting parts with @captures. Put this in ports.scm:
(pair
key: (key) @name
value: (value (number)) @port)
And run it:
tree-sitter query ports.scm example.kv
example.kv
pattern: 0
capture: 0 - name, start: (2, 0), end: (2, 4), text: `port`
capture: 1 - port, start: (2, 7), end: (2, 11), text: `8080`
Highlighting in editors is the same mechanism applied to queries/highlights.scm, and the CLI can render it for you:
# Colourised terminal output
tree-sitter highlight example.kv
# Self-contained HTML with a line-number column
tree-sitter highlight --html --layout line-numbers example.kv > example.html
# Symbol tags from queries/tags.scm
tree-sitter tags example.kv
Compiling Parsers and Opening the Playground
# Shared library for native hosts (kv.so)
tree-sitter build
# WebAssembly module (tree-sitter-kv.wasm)
tree-sitter build --wasm
# Browse trees and try queries in the browser
tree-sitter playground
On its first run, build --wasm fetches the WASI SDK and wasm-opt into ~/.cache/tree-sitter/, so it needs to be online once. Build the .wasm before starting the playground, since that is what it loads. As with upstream’s own binaries, loading Wasm parsers in parse and test and the embedded playground are available on amd64 and arm64.
Using Your Grammars from Anywhere
Outside a grammar repository the CLI needs to know where to look for parsers. Generate a configuration file:
tree-sitter init-config
It lands in ~/.config/tree-sitter/config.json. The parser-directories entry lists folders such as ~/github, ~/src and ~/projects; adjust it to wherever your tree-sitter-* checkouts live, then list what was discovered:
tree-sitter dump-languages
After that, parse, highlight and query choose a parser from the file extension, or from --scope source.kv when you need to be explicit.
Tree-sitter CLI and Neovim
On its current main branch, nvim-treesitter builds parsers on your machine using the Tree-sitter CLI and a C compiler. Noble’s archive version, 0.20.8, is far too old for it, which makes this package a natural fit. Once installed, run:
:checkhealth nvim-treesitter
Keeping tree-sitter-cli Updated
The Tree-sitter CLI rides along with your normal Ubuntu upgrades:
sudo apt update && sudo apt upgrade
When a newer release appears in deb.griffo.io, apt upgrade installs it alongside your other packages. Parsers are generated for a specific ABI version and grammar projects tend to move to new CLI features quickly, so a current CLI saves you from version-mismatch errors when you clone or update a grammar.
Other Tools from deb.griffo.io
The repository includes many tools that sit well next to the Tree-sitter CLI:
- Neovim - the hyperextensible Vim-based text editor, with Tree-sitter behind its syntax highlighting.
- Helix - a post-modern modal editor built around Tree-sitter from day one.
- Zed - a fast, collaborative code editor that parses every buffer with Tree-sitter.
- just - a command runner for keeping
tree-sitter generateandtree-sitter testone short recipe away.
Troubleshooting
GPG or Key Errors
If APT flags the repository as unsigned or the key as invalid, re-import it:
curl -fsSL https://deb.griffo.io/EA0F721D231FDD3A0A17B9AC7808B4DD62C41256.asc | sudo gpg --dearmor --yes -o /etc/apt/keyrings/deb.griffo.io.gpg
sudo apt update
Package Not Found
If APT cannot locate tree-sitter-cli:
- Re-run
sudo apt updateafter adding the repository. - Verify your Ubuntu release is supported (Jammy, Noble, Questing, or Resolute).
- Check that
dpkg --print-architecturereports amd64, arm64, armhf or i386. - Check the source list:
cat /etc/apt/sources.list.d/deb.griffo.io.list.
Also make sure you asked for the package, not the command: there is no package called tree-sitter.
Ubuntu’s Archive Version Got Installed
If tree-sitter --version shows an old release such as 0.20.8, the universe package won. See which versions APT knows about:
apt policy tree-sitter-cli
Then request the deb.griffo.io build by its exact version, as printed by apt policy:
sudo apt install tree-sitter-cli=0.27.0-1~noble
To make APT favour this repository for good, even if Ubuntu later catches up to the same upstream version, add /etc/apt/preferences.d/tree-sitter-cli:
Package: tree-sitter-cli
Pin: origin deb.griffo.io
Pin-Priority: 900
An Older tree-sitter Shadows the Package
Because the CLI is also published to crates.io, npm and GitHub releases, a copy installed that way can take priority over the packaged binary:
which -a tree-sitter
Uninstall it with the tool that put it there (cargo uninstall tree-sitter-cli or npm uninstall -g tree-sitter-cli), or remove a hand-extracted binary from /usr/local/bin, so that /usr/bin/tree-sitter wins.
Build, Test or Generate Fails
Failed to execute the C compiler- no compiler is installed; fix it withsudo apt install build-essential.tree-sitter generatecannot findnode- install Node.js, or use--js-runtime native.version `GLIBC_2.39' not found- typical on Jammy when upstream’s release binary is on yourPATHahead of this package. Locate it withwhich -a tree-sitterand delete it.
Uninstalling
Remove the Tree-sitter CLI with:
sudo apt remove tree-sitter-cli
To also remove the repository and key:
sudo rm /etc/apt/sources.list.d/deb.griffo.io.list
sudo rm /etc/apt/keyrings/deb.griffo.io.gpg
sudo apt update
APT does not touch ~/.config/tree-sitter/ or the compiled parsers and toolchains cached in ~/.cache/tree-sitter/; remove those yourself if you want a clean slate.
Conclusion
On Ubuntu, deb.griffo.io turns the Tree-sitter CLI into a first-class APT package: the current release on every supported version from Jammy to Resolute, no Rust or Node.js toolchain, no manual downloads. Grammar scaffolding, parser generation, corpus tests, queries, highlighting and a browser playground all come in one tree-sitter binary, maintained with apt upgrade.
If you write grammars, tweak highlight queries for your editor or just need an up-to-date CLI for nvim-treesitter, installing it this way keeps Tree-sitter ready on every machine and effortless to keep current.
Frequently Asked Questions
How do I install the latest tree-sitter-cli on Ubuntu?
Add the deb.griffo.io APT repository and its signing key, then run sudo apt install tree-sitter-cli. The repository tracks upstream Tree-sitter releases, so you get the latest packaged version without installing Cargo or npm.
Is there a .deb package for tree-sitter-cli?
Yes. deb.griffo.io publishes tree-sitter-cli as a signed .deb for Ubuntu. You could download that .deb and install it by hand, but adding the repository is the better option: APT then picks up new versions on its own.
How do I update tree-sitter-cli to the latest version?
Run sudo apt update && sudo apt upgrade. Once tree-sitter-cli is installed from APT there is no separate updater to remember, since new releases arrive with the rest of your system updates.
I installed tree-sitter-cli, so why is there no tree-sitter-cli command?
The package name and the command differ. tree-sitter-cli is what you install, following Ubuntu’s own package and the upstream crate name, while the executable is tree-sitter, exactly as the upstream documentation uses it.
Can I generate parsers without Node.js?
Yes. tree-sitter generate --js-runtime native evaluates grammar.js with the QuickJS engine embedded in the CLI. Set TREE_SITTER_JS_RUNTIME=native to avoid typing the flag each time.
How do I install tree-sitter-cli on Debian?
Exactly the same way; lsb_release -sc simply resolves to a different codename. There is a companion guide with the Debian specifics: How to install tree-sitter-cli on Debian.
Which Ubuntu releases are supported?
Jammy 22.04 LTS, Noble 24.04 LTS, Questing 25.10 and Resolute 26.04 LTS, on amd64, arm64, armhf and i386. Because the repository line is built from lsb_release -sc, the matching suite is selected for you.
Resources
- Tree-sitter Documentation
- Tree-sitter GitHub Repository
- tree-sitter-cli Packaging Repository
- deb.griffo.io Repository
- Install guide on deb.griffo.io
Disclaimer: The deb.griffo.io repository is an unofficial community project and is not affiliated with the official Debian or Ubuntu projects, or with the upstream Tree-sitter project.