Using Emacs 29+ Built‑in Tree‑sitter for Reliable Syntax Highlighting
Learn how to enable Emacs 29’s built‑in Tree‑sitter for accurate syntax highlighting and structural editing, with a Python example, setup steps, and notes on limitations.
21 Jan 2026, 00:22 UTC

The problem: regex‑based highlighting can drift while you edit
Emacs traditionally uses font‑lock with regular expressions to colour source code. When you type an incomplete construct – for example, an opening brace without its closing partner – the regex engine may mis‑colour the following lines until the buffer is re‑parsed. This can be distracting and makes structural commands like forward-sexp unreliable because they still operate on the naïve parenthesis‑based scan.
Enabling Tree‑sitter in Emacs 29+
Starting with Emacs 29.1 the editor ships a native Tree‑sitter library and an Elisp API (treesit-*). Major modes that have a -ts-mode variant (e.g., python-ts-mode, c-ts-mode) will automatically use Tree‑sitter if the corresponding grammar library (libtree-sitter-.so on Linux, .dll on Windows) is found at runtime. No extra packages are required; you only need to install the grammar files.
Installing a grammar (Linux example)
- Open a terminal.
- Install the grammar package for the language you want, e.g., for Python:
Where to run: any shell; Permissions: root (viasudo apt-get install tree-sitter-pythonsudo) to modify system directories. - Verify that Emacs can locate the library:
The command should return a non‑nil value (typically the absolute path toM-: (treesit-grammar-available-p 'python)libtree-sitter-python.so). If it returnsnil, check that the library is in a directory on Emacs’s dynamic‑loader search path (e.g.,/usr/lib/tree-sitter) or add that directory told-library-pathbefore starting Emacs.
Switching to the Tree‑sitter variant of a mode
Once the grammar is loadable, simply invoke the -ts-mode command. For a Python file:
M-x python-ts-mode
You can also make it the default by adding to your init file:
(add-to-list 'auto-mode-alist '("\\.py$" . python-ts-mode))
Worked example: Python f‑strings and match statements
Open a fresh test.py buffer and enable Tree‑sitter:
M-x python-ts-mode
Now type the following code (point shown as |):
def example(name: str) -> str: return f"Hello, {name}|" match value: case 0: pass case _: print("other")With Tree‑sitter active, the
f"..."string is coloured as a single literal, and thematchblock is highlighted according to the@keyword.capturecaptures defined in the grammar’s query file. If you switch back to the legacy mode (M-x python-mode) you will notice that the interior of the f‑string may be incorrectly coloured as separate tokens while you are typing.Test structural navigation: place the cursor inside the
f"..."expression and pressC-M-f(forward-sexp). The point jumps past the entire formatted string as a single syntax node, not merely to the next parenthesis.Trade‑offs and limitations
- Memory: Each buffer retains the full concrete syntax tree, which can add tens of megabytes for large files. On very old hardware or files exceeding ~100 k lines you may notice a slight slowdown compared with the lightweight regex engine.
- Grammar version compatibility: The Tree‑sitter C library bundled with Emacs expects a specific ABI. If a system‑provided
libtree-sitter-.sois built from a mismatched version, Emacs may silently fall back to regex or, rarely, crash. Pinning to the distribution’s version that matches the Emacs release (or building grammars from theemacs-tree-sitterrepository) avoids this. - Maturity of indentation queries: Indentation relies on Tree‑sitter queries that are still evolving. Languages with complex templates (C++) or generics (TypeScript) may mis‑indent until the upstream queries are refined.
- Windows DLL discovery: On Windows the grammar DLL must reside in the same directory as
emacs.exeor somewhere on thePATH. WSL2 users should install grammars inside the Linux distribution, not the Windows filesystem, otherwise Emacs cannot load them.
Practical verification steps
- Confirm you are running Emacs ≥ 29.1:
emacs --version. - Run
M-x treesit-ready-p; it should returntif any grammar loaded. - Open a file of a language with a
-ts-modevariant and runM-x describe-mode. The mode line should show, for example, “Python‑TS”. - Launch
M-x treesit-inspect-modeto inspect the live syntax tree; navigating the tree with arrow keys should reflect the actual source structure. - Disable Tree‑sitter temporarily with
M-x python-mode(or the appropriate legacy mode) and compare highlighting of recent language features (f‑strings, match statements, decorators). The Tree‑sitter version should stay correct during incremental edits.
Actionable closing
If you are using Emacs 29+ and work with languages that ship a -ts-mode variant, install the corresponding grammar package via your system’s package manager, start the -ts-mode command, and verify with treesit-grammar-available-p and treesit-inspect-mode. Keep an eye on memory usage for huge files and consider pinning grammar versions if you encounter silent fallbacks. The payoff is more reliable colouring, indentation, and structural navigation that stays correct as you type.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.