Linter / Formatter for Twig template files which respects HTML and your time.
- Fast
- written in Rust
- works on files concurrently
- Helpful
- provides rich error messages and suggestions most of the time
- Rule based
- Rules can annotate syntax and make suggestions
- Suggestions can be applied automatically with
--fix
- Configurable
- Rules can be ignored for the whole file or next line (which ignores the whole next SyntaxNode)
.ludtwig-ignoreto ignore whole files completely (like your.gitignore)ludtwig-config.toml(use-Cto create one) to configure the rules for your project / adjust the code style- Environment variables can override config values
- The Parser is not HTML Spec compliant, but
- All Twig syntax of the PHP Twig engine and Symfony + Shopware extensions are supported (on best effort basis)
- all input is parsed into a lossless syntax tree
- even invalid syntax does not stop the parsing, and it tries to parse as much valid syntax as possible
- Disclaimer: This project tries to follow the official Twig PHP compilers syntax (+ Symfony and Shopware extensions) but might not immediately support all the latest features
- You may encounter edge cases that result in parsing errors but are valid according to the PHP Twig compiler. If they follow ludtwig's rules (not cutting HTML with Twig), please create issues for them.
Run the following cargo command to install or update ludtwig:
cargo install ludtwig
You can install cargo here
If you don't want to install the rust toolchain / cargo you can still use the other methods below.
Download the latest release binary for your operating system and put it in your PATH for easy access.
Have a look at the docker image or try it with the following command to
lint the current working directory:
docker run --rm -v $(pwd):/work maltejanz/ludtwig:latest .
You can also use the nix package.
After the installation have a look at ludtwig --help for more information. It should be self-explanatory.
Also have a look at the default config file if you want to customize the way how ludtwig analyses your files.
To create it in your current working directory run ludtwig -C.
Ludtwig parses Twig and HTML into a single syntax tree. It analyzes complete HTML elements most precisely when they stay within the same Twig branch. Twig can also appear in attributes and across HTML tag boundaries:
{% block my_component %}
{% set isActive = true %}
<div id="my-component"
class="my-component {% if isLarge %}large{% endif %}"
{{ dataAttribute }}="data"
{# Single word attributes don't strictly require quotes #}
data-active={{ isActive }}
>
{% block my_component_inner %}
<span id="my-span"
{% if isActive %}
style="color: red"
{% endif %}
>
hello {{ name }}
</span>
{% endblock %}
</div>
{% endblock %}Ludtwig also parses HTML tags split across Twig branches, for example:
{% if condition %}
<div class="container">
{% endif %}
Some content
{% if condition %}
</div>
{% endif %}For split tags, the parser represents the opening and closing tags as separate syntax nodes. The html-tag-fragments
rule checks that they have the same Twig branch conditions and reports unmatched or improperly nested fragments. Ludtwig still analyzes their
attributes and contents. Conditions whose value changes between evaluations, or overridden Twig blocks, can change
the rendered HTML; keep complete HTML elements within a single Twig branch where possible.
Copyright (c) 2026 Malte Janz
ludtwig is distributed under the terms of the MIT License.
See the LICENSE file for details.
For testing purposes this repository also includes code from the following sources (not included in distributed binary):