skip to content

Project Isolation

Isolated Projects, which forbids cross-project access so configuration itself can run in parallel, building on the configuration cache model. Interviewers cite it as the reason cross-project configuration is now discouraged.

on this pageshow

questions

5

Why are root-level allprojects {} and subprojects {} blocks discouraged under Project Isolation, and what replaces them?

level: juniorimportance: should knowfreq 22%

answer

  1. Root mutates siblings = violation
  2. allprojects/subprojects forbidden
  3. Convention plugin in buildSrc
  4. Each project applies it via plugins { id(...) }
  5. Independent, parallel-configurable projects

basics

~10 s

Those blocks configure other projects from the root, which is exactly the cross-project mutation Project Isolation forbids. Replace them with convention plugins in buildSrc that each project applies itself.

solid answer

~40 s

`allprojects {}` and `subprojects {}` live in the **root** build script and reach down to configure every other project's mutable model. Project Isolation forbids one project from mutating another at configuration time, so these blocks are direct violations — they're the most common reason a build fails isolation. The replacement is a **convention (precompiled script) plugin**: put the shared logic in `buildSrc/src/main/kotlin/my.conventions.gradle.kts` (or an included build), then have each project `apply` it via `plugins { id("my.conventions") }`. Now each project configures **itself** with the shared behavior — no cross-project mutation — which keeps projects independent and lets Gradle configure them in parallel and incrementally. As a bonus, convention plugins are testable, reusable across builds, and don't rely on project evaluation order.

code

kotlin · 7 lines
kotlin
// buildSrc/src/main/kotlin/my.java-conventions.gradle.kts
plugins { `java-library` }
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
tasks.withType<Test>().configureEach { useJUnitPlatform() }

// each subproject's build.gradle.kts
plugins { id("my.java-conventions") }

go deeper

for a junior

Know that root allprojects/subprojects mutate other projects and that convention plugins applied per-project replace them.

for a middle

Explain why the mutation breaks isolation and how to structure conventions in buildSrc.

for a senior

Discuss migration: splitting conventions, included builds, and avoiding reintroducing root mutation.

for a principal

Define the org convention-plugin standard so large builds stay isolation-compliant by default.

## What these blocks do In many older Gradle builds the root `build.gradle(.kts)` contains: ```kotlin subprojects { apply(plugin = "java-library") tasks.withType<Test>().configureEach { useJUnitPlatform() } } ``` This runs from the **root project** and **mutates every subproject's model**. It's convenient but it means the root is configuring code that belongs to other projects. ## Why Project Isolation rejects it Project Isolation's core rule: a project may only configure **itself**. `allprojects`/`subprojects` violate this by definition — the root mutates siblings. That coupling is what prevents Gradle from configuring projects independently, so isolation reports it as a violation. (It's also fragile without isolation: it depends on evaluation order and makes builds hard to reason about.) ## The replacement: convention plugins Move shared configuration into a **precompiled script plugin** in `buildSrc`: ```kotlin // buildSrc/src/main/kotlin/my.java-conventions.gradle.kts plugins { `java-library` } java { toolchain { languageVersion = JavaLanguageVersion.of(21) } } tasks.withType<Test>().configureEach { useJUnitPlatform() } ``` Then each project opts in: ```kotlin // lib/build.gradle.kts plugins { id("my.java-conventions") } ``` Now: - Each project applies the convention to **itself** — no cross-project mutation. - Projects stay independent, so Gradle can configure them in parallel and cache each separately. - The convention is explicit per project (you can see what applies), testable, and reusable across builds (publish it from an included build if needed). ## Migration tips - Group related conventions into multiple small plugins (java, testing, publishing) rather than one mega-plugin. - Apply them by `id` in each project, not via `apply(from = ...)` of arbitrary scripts. - Avoid putting back any `allprojects`/`subprojects` mutation 'just for one thing' — it reintroduces the violation. ## Net effect Replacing root-driven mutation with per-project convention application is usually the single biggest step in making a build Project-Isolation-compliant.

  • Is allprojects {} ever acceptable if it only reads, never mutates?
    Even reads can pull in another project's mutable model and they encourage coupling; under Project Isolation the safe approach is per-project convention plugins. Prefer eliminating the block entirely.
  • Where should a convention plugin live?
    In buildSrc (auto-available to the build) or in a separate included build you composite in via includeBuild — both let each project apply it by id without cross-project mutation.

It's the difference between a manager personally rearranging everyone's desk (allprojects) versus handing each person the same checklist to set up their own desk (convention plugin) — the latter scales and lets everyone work at once.

saying these in an interview costs you the question

  • Saying allprojects/subprojects is fine as long as it's in the root (the root mutating siblings is the violation).
  • Replacing the block with cross-project apply(from = ...) hacks instead of real convention plugins.

context

open as a page

What is Gradle's Project Isolation feature, and how do you enable it?

level: middleimportance: should knowfreq 35%

basics

~10 s

Project Isolation makes each project's configuration independent so projects can't reach into each other at configuration time. You enable it with the flag org.gradle.unsafe.isolated-projects=true in gradle.properties.

open as a page

What kinds of cross-project access does Project Isolation forbid, and how do you refactor a build to be isolation-compliant?

level: seniorimportance: should knowfreq 28%

basics

~20 s

It forbids one project reaching into another's mutable model at configuration time — e.g. reading or mutating another project's tasks, extensions, or properties. You fix it by using dependencies, shared lazy Providers, and convention plugins instead.

open as a page

How does Project Isolation build on and differ from the configuration cache?

level: seniorimportance: should knowfreq 24%

basics

~20 s

The configuration cache stores the whole configuration phase result and reuses it when inputs are unchanged. Project Isolation extends that to a per-project granularity, so projects configure in parallel and only changed projects are reconfigured.

open as a page

What performance benefits does Project Isolation deliver, and what are the trade-offs of adopting it today?

level: middleimportance: nice to knowfreq 20%

basics

~10 s

It speeds up large multi-project builds via parallel and incremental configuration, so only changed projects reconfigure. The trade-off: it's incubating, needs cross-project access removed, and not all plugins are compatible.

open as a page