Skip to content

tree-sitter.zig โ€‹

A native Zig implementation of the Tree-sitter parsing runtime.

Fast, incremental, dependency-free parsing for Zig 0.16.0 โ€” no C code, no Rust, no @cImport. Just Zig and its standard library.

What is tree-sitter.zig? โ€‹

Tree-sitter is a parsing strategy built for developer tools: instead of parsing a file once and throwing the result away, it keeps a concrete syntax tree alive, updates it cheaply on every keystroke, and lets tools ask structural questions about code.

tree-sitter.zig implements that runtime natively in Zig:

zig
const treesitter = @import("treesitter");

var parser = treesitter.Parser.init(allocator);
defer parser.deinit();
try parser.setLanguage(my_language);

var tree = try parser.parseString("1 + 2 * 3");
defer tree.deinit();

const root = tree.rootNode(); // lightweight handle, no allocation

Features โ€‹

LR parsing engine

Table-driven shift / reduce / accept with lookahead, implemented from scratch in Zig.

Learn more โ†’

Incremental parsing

Pass an old tree plus an edit; unaffected subtrees are reused, not re-parsed.

Learn more โ†’

Structural queries

S-expression patterns with captures, fields, quantifiers, and predicates.

Learn more โ†’

Error recovery

Malformed input yields ERROR and MISSING nodes instead of failures.

Learn more โ†’

Explicit allocators

Pass an allocator once to Parser.init; everything else inherits it.

Learn more โ†’

Dependency-free

Zig 0.16.0 standard library only. No C runtime, no Rust.

Learn more โ†’

Quick Start โ€‹

zig
var parser = treesitter.Parser.init(allocator);
defer parser.deinit();
try parser.setLanguage(my_language);

var tree = try parser.parseString("a + b");
defer tree.deinit();

var query = try parser.compileQuery("(identifier) @id");
defer query.deinit();

var qcursor = parser.queryCursor();
defer qcursor.deinit();
try qcursor.execute(my_language, query.patterns(), query.nodes(), query.captureNames(), &tree);
while (qcursor.nextMatch()) |m| {
    for (m.captures) |cap| std.debug.print("@{s}: {s}\n", .{ cap.name, cap.node.text() });
}

Read the Getting Started guide, browse runnable examples, or jump to the API reference.

Architecture โ€‹

text
                    tree-sitter.zig
                           โ”‚
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚                  โ”‚                  โ”‚
      Parser             Tree              Query
        โ”‚                  โ”‚                  โ”‚
   โ”Œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”
   โ”‚    โ”‚    โ”‚       โ”‚     โ”‚     โ”‚       โ”‚    โ”‚    โ”‚
 Lexer Stack Actions Node Cursor Edit  Pattern Capture Matcher
   โ”‚
 Input
   โ”‚
 Unicode
   โ”‚
 Language

See Architecture for the full picture.

Core Concepts โ€‹

  • Parser โ€” turns source text into a syntax tree.
  • Nodes โ€” lightweight handles into the tree.
  • Cursors โ€” allocation-free tree traversal.
  • Incremental parsing โ€” reparse only what changed.
  • Queries โ€” structural search with captures.

Use Cases โ€‹

From syntax highlighting to editor integration and static analysis โ€” if your tool reads code structurally, start with the use cases.

Performance โ€‹

On an ~80KB expression corpus (100,000 nodes, ReleaseFast): initial parse ~10 ms, worst-case incremental edit ~4โ€“16 ms with ~40,000 reused subtrees, traversal ~1 ms, 20,000 query matches in ~4 ms. Details and reproduction steps: Performance.

Compatibility โ€‹

Windows, Linux, and macOS across x86, x86_64, and ARM64 โ€” validated with Zig 0.16.0. See the compatibility matrix.

GitHub & Community โ€‹

Released under the MIT License.