Which tasks does the `idea` plugin add in a multi-project build, and how do `idea`/`cleanIdea` behave across the project tree?
answer
- ideaModule per project
- ideaProject + ideaWorkspace root-only
- idea = aggregate lifecycle task
- cleanIdea deletes
- ./gradlew idea regenerates whole tree
basics
~10 sEach project gets ideaModule (and the root also gets ideaProject/ideaWorkspace). The aggregate idea task runs them all; cleanIdea deletes the generated files. Running ./gradlew idea from the root regenerates the whole tree.
solid answer
~40 sApplying `idea` adds, per project, an `ideaModule` task that writes that project's `.iml`. The **root** project additionally gets `ideaProject` (writes `.ipr`) and `ideaWorkspace` (writes `.iws`). The lifecycle task `idea` aggregates these — at the root it transitively triggers every subproject's `ideaModule` plus the root's project/workspace tasks, so one `./gradlew idea` regenerates the entire tree. Symmetrically, `cleanIdea` (and the underlying `cleanIdeaModule`/`cleanIdeaProject`/`cleanIdeaWorkspace`) removes the files. Because these are normal tasks, they participate in the task graph and can be wired with `dependsOn`/`finalizedBy`. The plugin is typically applied to all projects via `allprojects { apply(plugin = "idea") }` (or each subproject), with the `project` block configured only at the root since the `.ipr` is singular.
code
bash · 8 lines# regenerate the entire multi-project IDE metadata
./gradlew idea
# regenerate just one module's .iml
./gradlew :payments:ideaModule
# remove all generated files
./gradlew cleanIdeago deeper
Name the idea and cleanIdea tasks and that idea generates the files.
Distinguish ideaModule (per project) from ideaProject/ideaWorkspace (root) and the aggregate behavior.
Explain wiring these tasks into the graph (dependsOn/finalizedBy) and when generation matters in multi-project CI.
Decide whether the team runs generation at all and govern consistency of applying the plugin across the module tree.
## Tasks added by the plugin For a project that applies `idea`: - **`ideaModule`** — generates this project's `.iml`. Added to *every* project. - **`ideaProject`** — generates the `.ipr`. Added **only to the root** project. - **`ideaWorkspace`** — generates the `.iws`. Added **only to the root**. - **`idea`** — a lifecycle/aggregate task. On the root it depends on `ideaProject`, `ideaWorkspace`, and (transitively) the `ideaModule` of each project; on a subproject it just runs that project's `ideaModule`. - **`cleanIdea`** + `cleanIdeaModule` / `cleanIdeaProject` / `cleanIdeaWorkspace` — the matching deletion tasks, generated by the `base`/clean conventions. ## Multi-project behavior ```bash # from the root: ./gradlew idea # regenerate .ipr + .iws + every subproject .iml ./gradlew cleanIdea # delete them all # scoped to one subproject: ./gradlew :feature-a:ideaModule ``` Running `idea` at the root is the canonical "regenerate everything" command. Running a subproject's `ideaModule` regenerates just that `.iml`. ## Typical application pattern ```kotlin // root build.gradle.kts allprojects { apply(plugin = "idea") } idea { project { // root-only block jdkName = "21" languageLevel = "21" } } ``` Apply broadly so every module gets an `.iml`; configure the `project` block once at the root. ## They're ordinary tasks Because `ideaModule` etc. are real tasks, you can hook them: `tasks.named("ideaModule") { dependsOn(someGenerationTask) }` to ensure generated sources exist before the `.iml` is written, or `finalizedBy` to post-process. They're also incremental in the sense that re-running with no model change rewrites deterministically. ## Reminder All of this is the **generation** path. With native import you never run these tasks; IDEA imports the model directly.
- Why is there no `ideaProject` task on subprojects?There is a single `.ipr` for the whole build and it belongs to the root, so only the root gets `ideaProject` (and `ideaWorkspace`). Subprojects only contribute their `.iml` via `ideaModule`.
- How would you ensure generated sources exist before the `.iml` is written?Wire a dependency: `tasks.named("ideaModule") { dependsOn("generateSources") }`, since `ideaModule` is an ordinary task in the graph.
saying these in an interview costs you the question
- Expecting an `ideaProject` task on every subproject.
- Thinking `cleanIdea` also clears IDEA's caches — it only deletes the generated files.
- Assuming you must run `idea` to use IntelliJ — native import needs none of these tasks.