# How to Add Support for a Custom Language in CRG: TOML Configuration Guide

> Easily add custom language support to Code Review Graph CRG. Map file extensions to Tree-sitter grammars using a simple TOML configuration file without code changes.

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

---

**You can add support for a custom language in code-review-graph by creating a [`.code-review-graph/languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/.code-review-graph/languages.toml) file that maps file extensions to Tree-sitter grammars and node types, without modifying the core codebase or forking the repository.**

The `code-review-graph` (CRG) analyzer relies on Tree-sitter grammars from the `tree-sitter-language-pack` to parse source files. When you need to parse a language that isn't included as a built-in, you can extend support declaratively using a TOML configuration file that defines node type mappings for functions, classes, imports, and call expressions.

## Creating the Configuration File

CRG looks for custom language definitions in a specific location within your repository. The loader checks for [`.code-review-graph/languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/.code-review-graph/languages.toml) as defined by the `CONFIG_RELATIVE_PATH` constant in [[`code_review_graph/custom_languages.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py)](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py#L47-L49).

### File Location

Create the configuration file at the repository root:

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

```

The `load_custom_languages()` function reads this file, caches the result, and validates each entry during the build process.

### Schema and Required Fields

Each language entry uses the `[languages.<name>]` table format. The language name must match the regex `^[a-z][a-z0-9_-]{0,31}$` (enforced by `_NAME_RE` in the validator).

Required keys include:

- **`extensions`**: Array of file extensions including the leading dot (must match `^\.[a-z0-9_+-]{1,15}$` per `_EXTENSION_RE`)
- **`grammar`**: Exact name of the grammar as it appears in `tree-sitter-language-pack`
- **Node type arrays** (at least one must be non-empty):
  - `function_node_types`: Tree-sitter node types representing function definitions
  - `class_node_types`: Tree-sitter node types representing class definitions  
  - `import_node_types`: Tree-sitter node types representing import statements
  - `call_node_types`: Tree-sitter node types representing call expressions

Optional fields include `name_field` (array of field names to locate definition names when default heuristics fail) and `comment` (human-readable note).

Here is a minimal example for Erlang as documented in [[`CUSTOM_LANGUAGES.md`](https://github.com/tirth8205/code-review-graph/blob/main/CUSTOM_LANGUAGES.md)](https://github.com/tirth8205/code-review-graph/blob/main/docs/CUSTOM_LANGUAGES.md#L12-L22):

```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"

```

And a minimal example for a fictitious language "foo":

```toml
[languages.foo]
extensions = [".foo"]
grammar = "foo"
function_node_types = ["def_func"]
class_node_types = ["def_class"]
import_node_types = ["import_stmt"]
call_node_types = ["call_expr"]
name_field = ["identifier", "name"]
comment = "Support for the Foo language via tree-sitter-language-pack"

```

## Validation Rules and Constraints

When `load_custom_languages()` executes (lines 10-28 in [`custom_languages.py`](https://github.com/tirth8205/code-review-graph/blob/main/custom_languages.py)), it performs strict validation on every entry:

- **Naming restrictions**: Custom languages cannot shadow built-in language names or claim extensions already handled by built-in parsers (see lines 24-30).
- **Grammar availability**: The specified grammar must be loadable via `tslp.get_language(grammar)` (lines 33-35); otherwise, the entry is skipped with a warning.
- **Quantity limit**: Maximum of **20** custom languages per repository (`MAX_CUSTOM_LANGUAGES`).
- **Pattern compliance**: Language names and extensions must match their respective regex patterns.

If any validation fails, the loader emits a warning via `logger.warning()` in `_validate_entry` and skips the invalid entry, continuing with the remaining configurations.

## Building the Graph with Custom Languages

After saving your configuration, you must trigger a fresh build to load the new grammar. The build process recreates the `CodeParser` instance, which invokes the generic walker in [[`parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/parser.py)](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py#L10622-L10630) to process the custom language using the same extraction logic as built-in languages.

Run the build command:

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

```

Files matching your declared extensions will now parse using the specified Tree-sitter grammar. The extracted entities appear in the graph with `language = "your_language"` attributes, and edges like `CALLS` and `IMPORTS_FROM` generate automatically based on your `call_node_types` and `import_node_types` mappings.

## Verifying Grammar Availability

Before configuring a language, verify that the grammar exists in the tree-sitter-language-pack:

```bash
uv run python - <<'EOF'
import tree_sitter_language_pack as tslp
print(tslp.get_language("erlang"))  # Replace with your grammar name

EOF

```

A `LookupError` indicates the grammar is not bundled and cannot be used until added to the language pack.

## Summary

- Create [`.code-review-graph/languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/.code-review-graph/languages.toml) in your repository root to add custom language support in CRG without code changes or forks.
- Define language entries with required fields: `extensions`, `grammar`, and at least one node type array (`function_node_types`, `class_node_types`, `import_node_types`, or `call_node_types`).
- Validation enforces unique names/extensions, available grammars via `tslp.get_language()`, and a maximum of 20 custom languages.
- Run `uv run code-review-graph build` to apply changes and parse files using the new configuration.
- Custom languages integrate fully with existing graph features including impact radius analysis and community detection via the generic walker.

## Frequently Asked Questions

### What file extensions are valid for custom languages?

Extensions must start with a dot and contain only lowercase letters, numbers, underscores, plus signs, or hyphens, matching the pattern `^\.[a-z0-9_+-]{1,15}$` enforced by `_EXTENSION_RE`. For example, `.erl` and `.foo` are valid, but extensions longer than 15 characters or containing uppercase letters will fail validation.

### Can I override a built-in language parser with a custom configuration?

No. The validator in [`code_review_graph/custom_languages.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py) explicitly prevents custom languages from shadowing built-in language names or claiming extensions already handled by built-in parsers (lines 24-30). If you attempt this, the loader will skip your entry and emit a warning via `logger.warning()`.

### What happens if I specify a grammar that isn't in the tree-sitter-language-pack?

The validation step calls `tslp.get_language(grammar)` to verify availability (lines 33-35). If the grammar is not found, the validator logs a warning and skips that language entry. The build continues, but files with matching extensions will not be parsed as that language.

### Do I need to restart the CRG server after adding a custom language?

No server restart is required, but you must run a fresh build using `uv run code-review-graph build`. The build process reinitializes the `CodeParser` and reloads the [`languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/languages.toml) configuration through `load_custom_languages()`, caching the validated results for the current analysis session.