Creating Queries
ts_query_new
Create a query by specifying a string containing one or more patterns.
Parameters
const TSLanguage*
required
The language to create the query for. Must match the grammar used to parse the target syntax trees.
const char*
required
A string containing one or more query patterns written in the query syntax.
uint32_t
required
The length of the source string in bytes.
uint32_t*
Output parameter. If there’s an error, this will be set to the byte offset where the error occurred.
TSQueryError*
Output parameter. If there’s an error, this will be set to the error type.
Returns
A pointer to aTSQuery object, or NULL if there was an error.
Error Handling
If the query has syntax errors or references invalid node types or fields, the function still returns aTSQuery, but error_offset and error_type indicate the problem.
The
TSQuery value is immutable and can be safely shared between threads.Error Types
TSQueryError
Enumerates possible query errors:
0
No error occurred. The query is valid.
The query has a syntax error. Check the S-expression structure.
The query references a node type that doesn’t exist in the grammar.
The query references a field name that doesn’t exist in the grammar.
The query has an invalid capture name or usage.
Creating Query Cursors
ts_query_cursor_new
Create a cursor for executing queries.
Returns
A pointer to a newTSQueryCursor object.
Executing Queries
ts_query_cursor_exec
Execute a query on a syntax node.
Parameters
TSQueryCursor*
required
The query cursor to use for execution.
const TSQuery*
required
The query to execute.
TSNode
required
The syntax tree node to search within. The query will match against this node and all its descendants.
Iterating Over Matches
Data Structures
The API provides structures for representing captures and matches:Represents a single captured node.
node: The captured syntax tree nodeindex: The index of the capture in the query (corresponds to the order of@capturenames)
Represents a complete pattern match.
id: Unique identifier for this matchpattern_index: Which pattern in the query matched (0-based)capture_count: Number of captures in this matchcaptures: Array of captured nodes
ts_query_cursor_next_match
Retrieve the next match from the query cursor.
Parameters
TSQueryCursor*
required
The query cursor to retrieve matches from.
TSQueryMatch*
required
Output parameter. Will be populated with the next match’s data.
Returns
trueif a match was found andmatchwas populatedfalseif there are no more matches
Example Usage
Basic Query Execution
Error Handling
Reusing Query Cursors
Memory Management
Query Lifecycle
Query Lifecycle
- Create with
ts_query_new() - Use across multiple threads (read-only)
- Delete with
ts_query_delete()when done - Deletion is thread-safe if no queries are executing
Cursor Lifecycle
Cursor Lifecycle
- Create with
ts_query_cursor_new() - Use for one or more query executions (single thread)
- Delete with
ts_query_cursor_delete()when done - Do not share cursors between threads
Match Data
Match Data
TSQueryMatchis populated by reference- The
capturesarray is valid until the next call tots_query_cursor_next_match() - Copy data if you need to retain it longer
Advanced Features
Query Introspection
Queries expose information about their structure:Query Predicates
Access predicates and directives programmatically:Predicate evaluation is typically implemented in language bindings, not the C library. The C API exposes predicates in structured form for bindings to interpret.
Language Bindings
Most users interact with queries through language bindings:Rust
tree-sitter crate provides idiomatic Rust API with predicate supportJavaScript
web-tree-sitter and Node bindings offer promise-based APIsPython
tree-sitter package provides Pythonic interface with predicate evaluation- Predicate implementation
- Iterator patterns
- Integration with language features
Performance Considerations
1
Share Queries
Create queries once and share them across threads. Query creation has overhead, especially for complex patterns.
2
Reuse Cursors
Within a thread, reuse query cursors for multiple executions. Cursor creation and deletion have some overhead.
3
Limit Query Scope
Execute queries on the smallest node that contains your target. Don’t query the entire tree if you only need a function body.
4
Optimize Patterns
More specific patterns (with field names and node types) are faster than generic ones. Use wildcards sparingly.
Next Steps
Query Syntax
Learn how to write query patterns
Predicates
Understand how to implement and use predicates
Parsers
Learn about parsing and syntax trees
Language Bindings
Explore Tree-sitter APIs in other languages