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 generate compiles a grammar.js into a portable C parser with no runtime dependencies.
  • 🧪 Corpus testing - Write inputs alongside their expected syntax trees and let tree-sitter test catch regressions.
  • 🔍 Terminal-first exploration - Query, highlight and tag real source files without writing a line of host code.
  • 🏗️ Ready-made project layout - tree-sitter init sets 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 .wasm module with --wasm.
  • 🕹️ Interactive playground - tree-sitter playground serves 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.html traces, conflict reports and a fuzzer for hard cases.

Why Use the deb.griffo.io Repository?

  • Easy installation and updates through APT rather than cargo or npm.
  • 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
  • sudo privileges
  • curl installed (sudo apt install curl if 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:

  1. Create the keyrings directory - makes sure /etc/apt/keyrings exists with the right permissions.
  2. Install the GPG key - downloads and de-armours the repository key into its own keyring so APT can verify signatures.
  3. Add the repository - writes a signed-by source line, letting lsb_release -sc fill in your Ubuntu codename.
  4. 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 generate and tree-sitter test one 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:

  1. Re-run sudo apt update after adding the repository.
  2. Verify your Ubuntu release is supported (Jammy, Noble, Questing, or Resolute).
  3. Check that dpkg --print-architecture reports amd64, arm64, armhf or i386.
  4. 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 with sudo apt install build-essential.
  • tree-sitter generate cannot find node - install Node.js, or use --js-runtime native.
  • version `GLIBC_2.39' not found - typical on Jammy when upstream’s release binary is on your PATH ahead of this package. Locate it with which -a tree-sitter and 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


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.