# How to Add a Custom Language to code-review-graph Using languages.toml

> Easily add a custom language to code-review-graph by configuring languages.toml. Learn to define grammars and map AST nodes for enhanced code review analysis.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-08-06

---

**You can add a custom language to code-review-graph by creating a [`languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/languages.toml) configuration file inside the `.code-review-graph/` directory at your repository root, defining the grammar from the bundled tree-sitter language pack, and mapping AST node types to graph entities.**

The `code-review-graph` tool provides extensibility for unsupported languages through a declarative TOML interface. By placing a [`languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/languages.toml) file in the hidden `.code-review-graph/` folder at your project root, you instruct the parser to load grammars from the bundled *tree-sitter-language-pack* and extract functions, classes, imports, and calls using the generic AST walker. This integration allows custom languages to participate fully in dependency analysis, impact-radius queries, and MCP tool interactions.

## Configuration File Location and Structure

The custom language loader expects the configuration file at a specific path relative to your repository root.

Create the file at:

```text
<repo_root>/.code-review-graph/languages.toml

```

Each language is defined as a TOML table under the `[languages.<name>]` namespace. The schema requires you to specify file extensions, the tree-sitter grammar name, and the node-type mappings that tell the walker which AST nodes correspond to functions, classes, imports, and calls.

## Required Configuration Schema

In [`code_review_graph/custom_languages.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py) (lines 48-78), the loader validates each language definition against a strict schema. You must provide the following keys inside each language table:

- **`extensions`** – Array of file extensions (e.g., `[".erl"]`) that identify source files for this language.
- **`grammar`** – String name of the tree-sitter grammar available in `tree_sitter_language_pack` (e.g., `"erlang"`).
- **`function_node_types`** – Array of AST node types representing function definitions.
- **`class_node_types`** – Array of AST node types representing class or type definitions.
- **`import_node_types`** – Array of AST node types representing import statements.
- **`call_node_types`** – Array of AST node types representing function calls.
- **`comment`** *(optional)* – Description for logging purposes.
- **`name_field`** *(optional)* – Specifies non-standard field names within AST nodes that contain the definition's identifier.

## How the Custom Language Loader Works

When you run a build, [`parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/parser.py) constructs a `CustomLanguages` instance that initiates a six-stage pipeline defined in [`custom_languages.py`](https://github.com/tirth8205/code-review-graph/blob/main/custom_languages.py) (line 116) and validated at line 77.

**1. File Discovery**
The loader checks for [`.code-review-graph/languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/.code-review-graph/languages.toml) and parses it using the TOML library.

**2. Schema Validation**
Each `[languages.<name>]` table is converted to a `CustomLanguage` object. The validator ensures extensions are unique, grammars are non-empty, and node-type lists are arrays.

**3. Conflict Handling**
Built-in languages always take precedence over custom definitions. Duplicate extensions are ignored, and the system enforces a maximum of 20 custom languages per repository.

**4. Grammar Loading**
The loader attempts to obtain a parser via `tslp.get_parser(grammar)`. If the specified grammar is not available in the bundled language pack, the entry is skipped with a warning.

**5. Node-Type Mapping**
The supplied node-type lists configure the generic walker to generate `Function`, `Class`, `IMPORTS_FROM`, and `CALLS` edges from the AST.

**6. Name Extraction**
If your grammar stores identifiers in non-standard fields (not the default `name` child), use `name_field` entries to direct the walker to the correct location.

## Step-by-Step Implementation

Follow these steps to register a custom language using the TOML configuration method.

### 1. Create the Configuration Directory and File

First, create the hidden directory and TOML file:

```bash
mkdir -p .code-review-graph
touch .code-review-graph/languages.toml

```

### 2. Define the Language Configuration

Edit [`languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/languages.toml) to declare your language. The following example registers Erlang using the bundled `erlang` grammar:

```toml

# .code-review-graph/languages.toml

[languages.erlang]
extensions = [".erl"]
grammar = "erlang"
function_node_types = ["function_clause"]
class_node_types = ["record_decl"]
import_node_types = ["import_attribute"]
call_node_types = ["call"]
comment = "Erlang via the bundled tree-sitter-erlang grammar"

```

Replace the values with the appropriate grammar and node-type names for your target language. The complete schema reference is documented in [`docs/CUSTOM_LANGUAGES.md`](https://github.com/tirth8205/code-review-graph/blob/main/docs/CUSTOM_LANGUAGES.md) (lines 37-56).

### 3. Build the Graph

Run the build command to compile the graph with your custom language:

```bash
uv run code-review-graph build

```

During initialization, you will see log output confirming the registration:

```text
INFO  Loading custom language 'erlang' from .code-review-graph/languages.toml

```

### 4. Verify Integration

Confirm that the custom language is indexed correctly using the Python API:

```python
from code_review_graph.parser import GraphBuilder

builder = GraphBuilder(repo_root=".")
builder.build()
count = builder.graph.nodes.filter(lambda n: n.language == "erlang").count()
print(f"Found {count} Erlang entities")

```

Alternatively, query the graph using MCP tools:

```bash
uv run code-review-graph query "language:erlang and type:Function"

```

Successful output confirms that `Function`, `Class`, and other entities are extracted and integrated into the graph.

## Summary

- **Create** a [`languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/languages.toml) file inside the `.code-review-graph/` directory at your repository root.
- **Define** the `grammar` string and node-type mappings (`function_node_types`, `class_node_types`, etc.) for the tree-sitter parser.
- **Validate** that the grammar exists in the bundled `tree_sitter_language_pack` or the loader will skip the entry with a warning.
- **Build** using `uv run code-review-graph build` to register the custom language and generate graph nodes.
- **Respect limits**: Maximum 20 custom languages per repository, and built-in languages override custom definitions with duplicate extensions.

## Frequently Asked Questions

### Where must I place the languages.toml file?

The file must reside at [`.code-review-graph/languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/.code-review-graph/languages.toml) relative to your repository root. The loader specifically checks this path during parser initialization in [`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py). Placing it elsewhere will prevent the `CustomLanguages` class from discovering your configuration.

### What grammars are available for custom languages?

You must use grammars available in the bundled *tree-sitter-language-pack*. The loader calls `tslp.get_parser(grammar)` to instantiate the parser. If you specify a grammar not included in the pack (such as a custom tree-sitter grammar not bundled with the tool), the entry is skipped with a warning. Check the `tree-sitter-language-pack` documentation for the full list of supported language identifiers.

### How do I handle languages that store identifiers in non-standard AST fields?

Use the optional `name_field` configuration key within your language table. This tells the generic AST walker which field contains the definition's name when it differs from the standard `name` child node. This is implemented in the name extraction logic of the walker to ensure `Function` and `Class` nodes receive correct labels.

### Why is my custom language not appearing in the graph after building?

First, check the build logs for validation warnings—common issues include unknown grammars (not in `tree_sitter_language_pack`), duplicate file extensions that conflict with built-in languages, or exceeding the 20-custom-language limit. Second, verify that your `extensions` array includes the leading dot (e.g., `[".erl"]` not `["erl"]`). Finally, ensure the TOML syntax is valid; malformed files are silently skipped by the loader in [`custom_languages.py`](https://github.com/tirth8205/code-review-graph/blob/main/custom_languages.py).