ktlint and detekt overlap on formatting. How do you decide which owns formatting, and how do you prevent ktlint disagreeing with IntelliJ's reformatter?
answer
- ktlint = formatting; detekt = smells/complexity
- detekt-formatting wraps ktlint -> don't double-run
- One formatting owner to avoid duplicate findings
- IntelliJ Reformat uses IDE code style -> drift
- .editorconfig + ktlint IDEA plugin = single source of truth
basics
~20 sLet ktlint own formatting and let detekt focus on code smells and complexity. To avoid fights with IntelliJ, point both ktlint and the IDE at the same .editorconfig so they format code the same way.
solid answer
~50 sktlint and detekt have overlapping scope because detekt ships a **`detekt-formatting`** add-on that *wraps ktlint's rules*. The clean separation is: **ktlint owns formatting/style** (indentation, imports, spacing) and **detekt owns smells/complexity/correctness-ish rules** (long methods, cyclomatic complexity, magic numbers, naming heuristics). Running ktlint's formatting rules from *both* tools causes duplicate/conflicting findings, so pick one — typically run ktlint standalone for formatting and either skip `detekt-formatting` or keep them aligned by sharing config. The other classic conflict is **ktlint vs IntelliJ's Reformat Code**: by default IntelliJ uses its own code-style settings, which can re-wrap or re-order in ways ktlint then flags. The fix is a single source of truth: drive both from **`.editorconfig`** with `ktlint_code_style = ktlint_official`, install the **ktlint IntelliJ plugin** (or enable IDEA's 'ktlint' mode / disable IDEA's conflicting reformat), and pin versions so everyone matches. Net: one formatter authority, one config file.
go deeper
Knows ktlint formats and detekt finds smells, and that the IDE should match the project style.
Avoids enabling detekt-formatting alongside ktlint and points IntelliJ at .editorconfig.
Cleanly assigns formatting ownership to ktlint, explains the detekt-formatting overlap and version drift, and eliminates IDE drift via .editorconfig + ktlint IDEA plugin + pinned versions.
Defines an org-wide formatting authority, standardizes IDE/CI config distribution, and reasons about tool coupling and upgrade cadence across the toolchain.
## The overlap problem - **ktlint** = formatter + style linter (anti-bikeshedding, official Kotlin style). - **detekt** = static analyzer for **code smells** and **complexity** (e.g. `LongMethod`, `ComplexCondition`, `MagicNumber`, `TooManyFunctions`). The overlap exists because detekt ships an optional module, **`detekt-formatting`**, which **re-exposes ktlint's formatting rules** as detekt rules (it depends on ktlint under the hood). If you enable `detekt-formatting` *and* run ktlint, the same formatting violation can be reported twice, and the two tools' versions can drift and disagree. ## Deciding ownership Pick **one owner for formatting**: - **Recommended:** ktlint owns all formatting/style; detekt is configured for smells/complexity only (do not enable `detekt-formatting`, or treat it as informational). - **Alternative:** if you want a single tool, use `detekt-formatting` for everything and drop standalone ktlint — but you inherit ktlint's rules through detekt's release cadence. Keeping them split keeps responsibilities crisp: ktlint = how code *looks*, detekt = how code is *structured*. Both read `.editorconfig`, so aligning them is mostly a matter of not double-reporting. ```text ktlint -> indentation, spacing, import order, wrapping (formatting) detekt -> long methods, complexity, magic numbers, naming smells ``` ## ktlint vs IntelliJ reformat IntelliJ's **Reformat Code** uses the IDE's *Code Style* settings by default. Those defaults differ from ktlint in places (continuation indent, import layout, trailing commas, wrapping), so a developer reformats in the IDE, commits, and CI's `ktlintCheck` then complains. To eliminate the loop: 1. **Single source of truth — `.editorconfig`.** ktlint reads it; IntelliJ also honors `.editorconfig` (enable 'Enable EditorConfig support'). Set `ktlint_code_style = ktlint_official` and the relevant `ij_kotlin_*` / `max_line_length` properties. 2. **Install the ktlint IntelliJ plugin**, which can run ktlint as the formatter and even auto-format on save, so the IDE *is* ktlint. 3. **Disable or align IDEA's conflicting Kotlin code-style** so its reformat matches ktlint_official (IDEA can import a ktlint-compatible style). 4. **Pin versions** of ktlint/plugins so every machine and CI agree. ## Mental model Think of `.editorconfig` as the constitution and ktlint as the supreme court for formatting. detekt is a different branch (structure/smells). IntelliJ should defer to the same constitution rather than enforcing its own.
- Why can enabling detekt-formatting cause confusing duplicate findings?detekt-formatting embeds ktlint's formatting rules, so the same issue is reported by both detekt and standalone ktlint, and their bundled ktlint versions can disagree.
- A teammate's IDE reformat keeps breaking ktlintCheck. What's the durable fix?Make IntelliJ honor the project .editorconfig (enable EditorConfig support) and/or install the ktlint IDEA plugin so the IDE formats with ktlint's rules instead of its own code style.
- If you want exactly one tool, what's the trade-off of using detekt-formatting only?You get a single binary but inherit ktlint's rules at detekt's release cadence, lagging upstream ktlint and coupling formatting upgrades to detekt upgrades.
ktlint and IntelliJ both formatting independently is two referees calling the same game with different rulebooks; .editorconfig hands them one rulebook.
saying these in an interview costs you the question
- Running ktlint and detekt-formatting both and being surprised by duplicate/conflicting findings
- Blaming ktlint for 'wrong' formatting when IntelliJ's own code style is the culprit
- Not knowing IntelliJ can read .editorconfig
- Thinking detekt is a formatter or ktlint detects complexity smells
- Letting each developer's IDE settings define formatting