Grammar-Kit turns a BNF file into IntelliJ parser and PSI code
Grammar files support & parser/PSI generation for IntelliJ IDEA
At a glance
- What is it?
- Grammar-Kit is the IntelliJ IDEA plugin used to write language support: it adds BNF and JFlex editing, a live preview of the parse tree, and a generator that produces the parser, element types and PSI classes for a new language. Its Gradle plugin has known limitations around mixins that the in-IDE generator does not have, and the plugin now requires Java 17.
- Who is it for?
- Adopt Grammar-Kit if you are writing a language plugin for IntelliJ IDEA and want the parser, element types and PSI generated rather than hand-written, since the live preview makes the grammar debuggable in a way generated-code workflows rarely are. Skip it if you rely on the mixin or psiImplUtilClass attributes and want build-time generation, because the Gradle plugin does not support them and the documentation tells you to commit the generated sources instead.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 31 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Six steps from a grammar file to a working language
The general usage instructions in the documentation are a six-step list, and it is worth reading as the shape of the whole workflow.
First, create a grammar .bnf file. Second, tune the grammar using Live Preview plus the Structure view, opened with Ctrl-Alt-P or Cmd-Alt-P. Third, generate the parser, ElementTypes and PSI classes with Ctrl-Shift-G or Cmd-Shift-G. Fourth, generate the lexer .flex file and then run the JFlex generator, both from the context menu. Fifth, implement ParserDefinition and add the corresponding registrations to the plugin.xml. Sixth, mix in resolve and other non-trivial functionality to the PSI.
The order matters, and the middle of it is the interesting part. A grammar is a design document before it is a code generator input, and the Live Preview exists so you can check what the grammar actually parses before generating anything. The structure view gives you the rule tree for the same purpose.
The two generated artifacts come from different places. The parser, element types and PSI come from Grammar-Kit itself, while the lexer is generated in two steps: Grammar-Kit produces the .flex file, and the JFlex generator turns that into the lexer. That split reflects how IntelliJ language support is usually structured, with a hand-specified lexer and a generated parser on top.
The documentation also points at the plugin's own source as the main example of a Grammar-Kit application, with the BNF parser and PSI generation grammar in the grammars directory.
The grammar language is PEG with attributes bolted on
The syntax is Parsing Expression Grammar, and the documentation gives a compact example of what it looks like:
// Basic PEG BNF syntax
root_rule ::= rule_A rule_B rule_C rule_D // sequence expression
rule_A ::= token | 'or_text' | "another_one" // choice expression
rule_B ::= [ optional_token ] and_another_one? // optional expression
rule_C ::= &required !forbidden // predicate expression
rule_D ::= { can_use_braces + (and_parens) * } // grouping and repetition
// Grammar-Kit BNF syntax
{ generate=[psi="no"] } // top-level global attributes
private left rule_with_modifier ::= '+' // rule modifiers
left rule_with_attributes ::= '?' {elementType=rule_D} // rule attributes
private meta list ::= <<p>> (',' <<p>>) * // meta rule with parameters
private list_usage ::= <<list rule_D>> // meta rule applicationThe `::=` symbol is used for what the documentation calls the left arrow symbol, and you can also use square brackets for optional sequences and brace-pipe-brace for choices, since those variants are popular in real-world grammars.
What Grammar-Kit adds on top of plain PEG is the attribute system. Attributes are name=value pairs enclosed in braces, and there are two levels. Top-level global attributes configure the generation as a whole, such as the example turning PSI generation off for a rule. Rule attributes apply to a single rule, and the modifiers in the example are `private`, `left` and `meta`.
The `left` modifier is the one that shows the design is not vanilla PEG. It is an associativity declaration, and it is what makes operator precedence tables work in a grammar that also has to be an expression language.
Meta rules with parameters, the `<<p>>` syntax, are the other extension, and they exist so a rule can be written once and instantiated with different parameters.
The Gradle plugin cannot resolve the mixin cycle, and the docs say why
Invoking the generator from the IDE is described as the preferred way, and the documentation is explicit about why the build-time path is different.
For build-time generation you use the gradle-grammar-kit-plugin, but two attributes are not supported there: `mixin` and `psiImplUtilClass`.
The reason given is a genuine circular dependency. Those attributes reference user-written classes that typically extend or implement the generated PSI interfaces, so compiling them requires the generator's output, while the generator in turn needs them to produce correctly-typed code. Resolving that cycle would require a two-pass build, which the Gradle plugin does not implement.
The in-IDE generator sidesteps the problem because it relies on IntelliJ's Java support, which tolerates incomplete code. That is the whole reason the IDE path is not just more convenient but strictly more capable.
There is a second, quieter consequence of the same limitation. Generic signatures and annotations on generated methods may not be correct, for the same reason: without access to the resolved types of referenced classes, the generator falls back to less precise signatures.
The workaround is stated directly. If your grammar relies on `mixin` or `psiImplUtilClass`, generate the parser and PSI from the IDE and commit the generated sources instead of running the generator from Gradle.
That is a real trade-off rather than a bug. You get build-time generation, correct mixin types and a reproducible pipeline, and you give up a single source of truth for the generated code, since a developer now has to remember to regenerate in the IDE and commit the result.
Kotlin Multiplatform parsers come out as Kotlin objects
There is one language-specific wrinkle in the generation, and it is documented precisely.
For Kotlin Multiplatform parsers using the syntax-api, you set `generate=[parser-api="syntax"]` in the grammar header. The parser is then generated as a Kotlin `object`. PSI classes are still generated as Java.
So the split is partial, and that is the important part. The parser becomes Kotlin, which is what the syntax-api expects, while the PSI stays Java, which keeps the rest of the IntelliJ platform integration unchanged. A project targeting Kotlin Multiplatform is therefore mixing generated languages by design rather than by accident.
The How-to document has a section on Kotlin parser generation with the syntax-api, and the details live there rather than in the README.
For everyone else, the generated output is the classic IntelliJ shape: a parser class, an ElementTypes holder with the token and element type constants, and PSI interfaces and implementations for the rules. Step five of the usage instructions is where you connect that to the platform, by implementing ParserDefinition and registering it in the plugin.xml, and step six is where the generated skeleton stops being enough and the resolve logic, which is usually the bulk of the real work, gets written by hand.
What the plugin does around the grammar, not just to it
The feature list is longer than a generator, and several items are the kind of editor tooling that a grammar author actually lives in.
On the refactoring side there is extract rule with Ctrl-Alt-M or Cmd-Alt-M, and introduce token with Ctrl-Alt-C or Cmd-Alt-C. On the editing side, you can flip choice branches intention via Alt-Enter, and unwrap or remove an expression with Ctrl-Shift-Del or Cmd-Shift-Del.
Navigation is well covered. There is a quick grammar and flex file structure popup with Ctrl-F12, go to related file for the parser and PSI with Ctrl-Alt-Home, and navigation to matched expressions with Ctrl-B inside an attribute pattern. That last one is the sort of detail that only matters if you have written attribute patterns, and it is a strong signal the plugin's author has.
Highlighting includes customizable colours through Settings and Colors and Fonts, pinned expression markers whose tooltip shows the pin value in charge, and a number of inspections listed in Settings and Inspections.
Documentation is provided through two popups: a rule documentation popup showing FIRST, FOLLOWS and PSI content with Ctrl-Q or Cmd-J, and an attribute documentation popup with the same shortcut.
There are also two diagram outputs, a PSI tree diagram that requires the UML plugin, and the Live Preview editor with a grammar evaluator that highlights as you start and stop it. The PSI tree diagram is the one that needs a third-party plugin, which is a small but real dependency for a language developer.
Who is already using it, and what the repository contains
The list of open-source plugins built with Grammar-Kit is the most convincing evidence about the tool, and it is not a short list.
Clojure-Kit, intellij-rust, intellij-erlang, intellij-elm, intellij-elixir, Perl5-IDEA, intellij-haxe and the Cypher plugin for graph databases are all listed, alongside the Dart plugin from JetBrains own intellij-plugins repository.
That range tells you two things. The first is that the tool handles very different language families, from Lisps to a systems language to a dynamically typed web language. The second is that the plugin is used by both individuals and by JetBrains itself, which is the strongest argument for a plugin whose output becomes part of a shipped IDE.
The repository layout shows the same story from the build side. There is a bnf-language/ directory for the BNF language support, a jflex-language/ directory for the JFlex support, a generator/ directory for the code generation, base/ for shared infrastructure, parser-runtime/ for what ends up in the plugin, grammars/ for the plugin's own grammars, and testData/ plus tests/ for the test suite. The antlr-based-bootstrap/ directory is worth noting, since it suggests the BNF parser itself was bootstrapped with an ANTLR grammar before the Grammar-Kit grammar took over.
The build is Gradle with build.gradle.kts, settings.gradle.kts, a gradle.properties and a gradlew wrapper, so the project is a normal IntelliJ plugin project. There is a qodana.yml for JetBrains' static analysis, a .idea/ directory checked in, and a grammar-kit.iml module file.
The licence situation needs a note. The licence field reads Other, a custom licence GitHub cannot classify, and points to the LICENSE file, while the badge in the README points to the Apache License 2.0. The LICENSE.md file in the repository is the document to read before you rely on the terms.
Since 2022.3 the plugin requires Java 17. The releases are named for IntelliJ platform versions, with 2023.3.4 published on 2026-07-09, 2023.3.3 on 2026-07-08 and 2023.3.1 on 2026-02-04, and the last push was on 2026-09-22.
Editorial conclusion
Adopt Grammar-Kit if you are writing a language plugin for IntelliJ IDEA and want the parser, element types and PSI generated rather than hand-written, since the live preview makes the grammar debuggable in a way generated-code workflows rarely are. Skip it if you rely on the mixin or psiImplUtilClass attributes and want build-time generation, because the Gradle plugin does not support them and the documentation tells you to commit the generated sources instead. Verify first that your IDE runs on Java 17 or newer, that you are on a recent plugin version, and whether your grammar needs the Kotlin Multiplatform syntax path, which changes the output language of the parser.
Frequently asked questions
What does Grammar-Kit do in IntelliJ IDEA?
It is a plugin for language plugin developers that adds BNF grammar and JFlex file editing support, along with a parser and PSI code generator. It also provides a live preview editor, a PSI tree diagram, refactorings and a set of inspections for grammar files.
How do I generate a parser and PSI with Grammar-Kit?
Create a grammar .bnf file, tune it with the Live Preview and Structure view, then press Ctrl-Shift-G or Cmd-Shift-G to generate the parser, ElementTypes and PSI classes. Generate the lexer .flex file from the context menu, run the JFlex generator on it, then implement ParserDefinition and register it in the plugin.xml.
Why does the Grammar-Kit Gradle plugin not support mixin attributes?
Those attributes reference user-written classes that extend or implement the generated PSI interfaces, so compiling them needs the generator output while the generator needs them for correct typing. Resolving that cycle would need a two-pass build, which the Gradle plugin does not implement, so the documentation recommends generating from the IDE and committing the sources.
Does Grammar-Kit generate Kotlin parsers?
For Kotlin Multiplatform parsers using the syntax-api, you set `generate=[parser-api="syntax"]` in the grammar header and the parser is generated as a Kotlin object. PSI classes are still generated as Java.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jetbrains-grammar-kit)Was this useful?