skip to content

What are ktlint's standard and experimental rule sets, and how do you opt into experimental rules safely?

level: middleimportance: should knowfreq 40%

answer

  1. Standard = stable & on; experimental = new & off
  2. ktlint_experimental = enabled to opt in
  3. Experimental rules may rename/promote/drop on upgrade
  4. Pin version + review diff after ktlintFormat
  5. Custom rule sets via RuleSetProvider JARs

basics

~20 s

The standard rule set is the stable, default set of style rules. The experimental set holds newer rules that are off by default; you turn them on in .editorconfig when you want to try them.

solid answer

~40 s

ktlint groups rules into **rule sets** identified by a prefix in their id: `standard:<rule>` and `experimental` rules (the experimental set). The **standard** set is enabled by default and is the stable, battle-tested baseline. The **experimental** set contains rules that are still being refined; they are **disabled by default** and you opt in with `ktlint_experimental = enabled` in `.editorconfig` (or enable individual experimental rules). Opting in safely means: enable it on a branch, run `ktlintFormat` to see the churn, review the diff, and pin your ktlint version so a future upgrade doesn't silently graduate or change a rule. Experimental rules may be promoted to standard, renamed, or removed across versions, so they shouldn't gate CI without a deliberate decision and a baseline. Third-party/custom rule sets can also be added via the plugin's `ruleSetProviders`/dependencies.

go deeper

for a junior

Knows experimental rules exist and are off by default.

for a middle

Can enable the experimental set in .editorconfig and explain that those rules are still evolving.

for a senior

Adopts experimental rules safely (pin version, review diff, baseline) and knows custom rule sets are possible.

for a principal

Sets org policy on rule-set adoption, manages upgrade/migration risk across many repos, and decides what gates CI.

## Rule sets A **rule set** is a named collection of rules. ktlint ships two first-party sets: - **Standard** (`ktlint_standard`) — the default, stable rules implementing the official Kotlin style. On unless you disable a specific rule. - **Experimental** (`ktlint_experimental`) — newer rules under evaluation. **Off by default.** They may change behavior, get renamed, be promoted into standard, or be dropped between releases. Each rule has a fully-qualified id, e.g. `standard:no-wildcard-imports`. You reference it in `.editorconfig` as `ktlint_standard_no-wildcard-imports`. ## Opting into experimental ```editorconfig [*.{kt,kts}] ktlint_experimental = enabled # enable the whole experimental set ktlint_experimental_<rule-id> = disabled # but keep one specific rule off ``` You can flip the polarity too — leave the set off and enable just one rule with `ktlint_experimental_<rule-id> = enabled` depending on version semantics; the cleanest mental model is: a rule runs only if its set and the rule itself are enabled. ## Doing it safely 1. **Pin the ktlint version** (Gradle plugin version) so behavior is reproducible. Experimental rules are the ones most likely to shift across upgrades. 2. **Enable on a branch**, run `./gradlew ktlintFormat`, and review the resulting diff — experimental rules can touch many files. 3. **Generate/refresh a baseline** if you adopt incrementally so the existing violations don't break CI immediately. 4. **Decide deliberately** before letting an experimental rule gate `ktlintCheck` in CI. ## Custom rule sets Beyond first-party sets, you can add **third-party rule sets** (custom `RuleSetProvider` JARs) for organization-specific conventions. These plug in alongside standard/experimental. ## Why the split exists The split lets the maintainers ship and iterate on new rules without forcing churn on every consumer, while keeping the default experience stable and low-friction — consistent with the anti-bikeshedding goal.

  • Why pin the ktlint/plugin version when using experimental rules?
    Experimental rules can change, be renamed, promoted to standard, or removed across versions; pinning keeps builds reproducible and avoids surprise CI failures on upgrade.
  • How would you add an organization-specific naming rule ktlint doesn't ship?
    Write a custom rule in a RuleSetProvider, package it as a JAR, and register it with the ktlint CLI/Gradle plugin as a custom rule set dependency.

saying these in an interview costs you the question

  • Assuming experimental rules are on by default
  • Enabling experimental and gating CI without reviewing churn
  • Not pinning the version, then blaming 'flaky' ktlint after an upgrade
  • Thinking you cannot add custom rules
  • Confusing rule sets with detekt rule sets

context