# Fernflower: the decompiler that shows source where IntelliJ has none

> Fernflower is JetBrains' Apache-2.0 analytical decompiler for Java, bundled with IntelliJ IDEA to display source when debugging or navigating class files, and runnable standalone from one jar. Its option set runs three dozen flags deep, from hiding bridge methods to emitting record patterns, with a renaming engine for obfuscated code and a per-method time budget for the pathological cases.

**JetBrains/fernflower** — Decompiler from Java bytecode to Java, used in IntelliJ IDEA.

- Repository: https://github.com/JetBrains/fernflower
- Website: https://github.com/JetBrains/intellij-community/tree/master/plugins/java-decompiler/engine
- Stars: 4,409 · Forks: 734
- Language: Java
- License: Apache-2.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/jetbrains-fernflower

## The decompiler inside every IntelliJ

Fernflower calls itself the first actually working analytical decompiler for Java and probably for a high-level programming language in general, a claim with teeth because it predates most of the field and still ships where the audience is largest, bundled in IntelliJ IDEA and primarily used to show Java code when debugging or navigating through class files. That bundling is the product decision that matters, decompiled output is treated not as a forensic specialty but as an ordinary view the IDE renders on demand. The repository is the engine directory of the IntelliJ Community project, contributions go by pull request into intellij-community following its guidelines, and bugs route to YouTrack under the subsystem Java. Decompiler. Engine. There are no GitHub releases, artifacts publish through the IntelliJ repository instead, and the last push landed 2026-09-29.

## One jar, three file types, recursion

Standalone use follows a compact grammar, java -jar fernflower.jar with any number of option=value pairs, one or more sources, and a destination directory:

```console
java -jar fernflower.jar [-<option>=<value>]* [<source>]+ <destination>
```

Sources may be files or directories, directories are scanned recursively, and the allowed extensions are class, zip and jar, so a jar file decompiles as a unit. A source prefixed with -e= is a library, not decompiled but taken into account when analyzing relationships between classes and methods, and the renaming option in particular benefits from information about external classes. The worked examples show both shapes:

```console
java -jar fernflower.jar -hes=0 -hdc=0 c:\Temp\binary\ -e=c:\Java\rt.jar c:\Temp\source\
```

decompiling a directory with the JDK runtime supplied as context, and a second form passing a jar and an individual class file together into one output directory.

## Six options for users, thirty more for professionals

The option table is explicitly stratified, typically the following options will be changed by user, if any, hes, hdc, dgs, mpm, ren, urc, and the rest can be left as they are, they are aimed at professional reverse engineers. The six user-facing ones cover the everyday judgments, hes and hdc control hiding empty super invocations and default constructors, dgs turns generic signature decompilation on, mpm bounds per-method processing time, ren renames obfuscated identifiers, and urc supplies a custom renamer class. The professional tier includes the structural decisions, rbr hiding bridge methods, rsy hiding synthetic class members, din decompiling inner classes, dc4 collapsing 1.4 class references, das decompiling assertions, den for enumerations, rgn removing getClass in qualified new statements, rer removing empty exception ranges, and fdi de-inline finally structures. With rare exceptions the value is 1 for activated and 0 for deactivated, and defaults are documented per flag.

## Flags named after compiler bugs

Three options exist purely because of javac history, and their descriptions say so. bto, interpret int 1 as boolean true, is a workaround to a compiler bug, for bytecode where the old compiler materialized booleans as integers. nns allows for a not set synthetic attribute, another compiler bug workaround, for classes whose synthetic markers went missing. And uto, considering nameless types as java.lang.Object, is a workaround to a compiler architecture flaw rather than a bug, the deeper kind of problem. Reading these flags is reading two decades of accumulated bytecode archaeology, each one a place where the mapping from source to class file was lossy or buggy in a way the decompiler now patches on the way back up. udv and ump belong to the same history from the other side, reconstructing variable and parameter names from debug information when the compiler preserved it.

## Modern Java gets its own switches

The option list tracks the language's evolution, which is what keeps a decompiler of this age current. For lambdas there are two positions, isl inline simple lambda expressions on by default, and lac decompiling lambda expressions to anonymous classes when you want the pre-Java-8 shape back. Records contribute ucrc, hiding unnecessary record constructor and getters, and crp, using record patterns where possible, while cps does the same for switch with patterns, the newer pattern matching constructs. cci checks whether a resource in try-with-resources actually implements AutoCloseable before trusting the syntax. Even output cosmetics moved with the times, pbo adds clarifying parentheses when bitwise or shift operators mix with arithmetic, acknowledging that precedence surprises are their own class of bug, and nls plus ind control newline style and the indentation string, three spaces by default.

## Renaming identifiers obfuscators ruined

The renaming subsystem addresses obfuscated code directly. Some obfuscators give classes and members short, meaningless and above all ambiguous names, and recompiling such code leads to a great number of conflicts, so it is advisable to let the decompiler rename elements in its turn, ensuring uniqueness of each identifier. Option ren activates it, and the default strategy renames an element if its name is a reserved word or shorter than 3 characters, generating new names in the pattern class, method or field underscore a consecutive unique number. For control over the rules, a class implementing org.jetbrains.java.decompiler.main.extern.IMemberIdentifierRenamer can be supplied through urc, available on the classpath, providing toBeRenamed plus one name provider each for classes, methods and fields, the full hook surface for a custom deobfuscation dictionary.

## A time budget per method

Decompilation is not uniformly cheap, and Fernflower admits it with mpm, the maximum allowed processing time per decompiled method in seconds, where 0 means no upper limit. The flag exists because some methods, whether through adversarial obfuscation or accidental pathology, can consume disproportionate effort, and a batch job decompiling a large jar needs to bound the damage rather than stall on one method. Paired with the log option, TRACE, INFO, WARN or ERROR with INFO as the default, a long run becomes observable, and iec, including the entire classpath in context when decompiling, trades analysis quality against memory for the cases where relationships span everything. These three together are the operational knobs for running Fernflower as infrastructure rather than interactively.

## Stiver's decompiler, maintained by JetBrains since 2014

The credits section carries the lineage. Fernflower was originally developed by Stiver, whose memorial blog post is linked from the README, and has been maintained by JetBrains since 2014. Patches from ForgeFlower, the MinecraftForge fork that grew out of the modding community's heavier demands on the decompiler, were merged back into this repository, and a mirror was maintained by Andrew McRae, fesh0r, for a very long time, serving as the standalone download most search results remember. The build is Gradle based, ./gradlew :installDist producing an executable startup script in build/install/engine/bin, the repository carries testData and test directories plus Bazel and IntelliJ module files, and the whole engine lives under the package org.jetbrains.java.decompiler, Apache-2.0 with a notice file.

## Conclusion

Use Fernflower when class files need to be read as Java, either ad hoc inside IntelliJ during debugging, where it already lives, or in bulk from the command line across jars and directories with the options tuned to the bytecode's era. For comparing output quality, test it against the alternatives on your actual jars rather than reputation, since decompiler strength varies by bytecode pattern. Before scripting it, decide the six options that matter for your use, hes, hdc, dgs, mpm, ren and urc in the project's own guidance, leave the specialist flags alone unless a specific artifact demands them, and pass library jars with -e= so the analysis sees the classes your target was compiled against, which measurably improves renaming and relationship recovery.

## FAQ

### what is fernflower decompiler?

Fernflower is an Apache-2.0 analytical Java decompiler, described by its authors as the first actually working one for Java, bundled with IntelliJ IDEA to display source when debugging or navigating class files and also runnable standalone from the command line. It has been maintained by JetBrains since 2014.

### how to use fernflower?

Run java -jar fernflower.jar with options, one or more sources and a destination directory, where sources are class, zip or jar files or directories scanned recursively, and -e= prefixed sources act as context libraries without being decompiled. Typical options to adjust are hes, hdc, dgs, mpm, ren and urc, with the rest aimed at professional reverse engineers.

### how to install fernflower?

Fernflower is bundled with IntelliJ IDEA, so IDEA users already have it, and standalone artifacts are published through the IntelliJ Community repository releases rather than GitHub. Building from source means cloning the repository and running ./gradlew :installDist, which generates a startup script under build/install/engine/bin.

### Is it possible to decompile a jar file?

Yes, with Fernflower a jar is one of the three allowed source extensions alongside class and zip, decompiled whole with one command, java -jar fernflower.jar with options, the jar path, and a destination directory, and directories of class files are scanned recursively the same way.

## Sources

- [Issues](https://github.com/JetBrains/fernflower/issues)
- [JetBrains/fernflower on GitHub](https://github.com/JetBrains/fernflower)
- [License: Apache-2.0](https://github.com/JetBrains/fernflower/blob/master/LICENSE)
- [Project website](https://github.com/JetBrains/intellij-community/tree/master/plugins/java-decompiler/engine)
- [README](https://github.com/JetBrains/fernflower/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jetbrains-fernflower
