What are the rules and gotchas around file placement, packages, and ids for precompiled convention plugins?
answer
- src/main/kotlin + kotlin-dsl
- id = filename minus .gradle.kts
- dotted filename → dotted id
- package is prepended to id
- includeBuild in pluginManagement
basics
~20 sPlace *.gradle.kts files in src/main/kotlin of a kotlin-dsl project. The plugin id is the filename minus .gradle.kts. A package declaration namespaces the generated class but does not change the id; the dotted filename itself forms the id.
solid answer
~40 sPrecompiled Kotlin convention scripts must live in **`src/main/kotlin`** (Groovy ones in `src/main/groovy`) of a project applying **`kotlin-dsl`** (or `groovy-gradle-plugin`). The **plugin id equals the filename with `.gradle.kts` stripped**, so `com.acme.java-conventions.gradle.kts` → id `com.acme.java-conventions`. To namespace, you can put the file in a package directory and add a `package com.acme;` declaration *at the top of the script* — but be careful: in Gradle the recommended way to namespace is simply to use a **dotted filename** (`com.acme.foo.gradle.kts`). If you use a package directory plus `package` statement, the package name is **prepended** to the plugin id. Filenames can't contain characters illegal in plugin ids, and the id must be a valid plugin id (dotted, lowercase-friendly). The enclosing build (`build-logic`) is wired via `includeBuild` in `pluginManagement` so consumers can apply by id.
code
bash · 6 lines# Both produce plugin id `com.acme.java-conventions`:
# (A) dotted filename, no package directory
build-logic/src/main/kotlin/com.acme.java-conventions.gradle.kts
# (B) package directory + `package com.acme` at top of file
build-logic/src/main/kotlin/com/acme/java-conventions.gradle.ktsgo deeper
Know files go in src/main/kotlin and the id is the filename.
Explain the package-prepended-to-id rule and the dotted-filename alternative, plus the includeBuild wiring.
Advise a single naming convention org-wide and explain the common doubled-prefix mistake.
Set a naming standard (namespace prefix per org/team) enforced across repos for discoverability and collision-avoidance.
## Where files go - Kotlin convention plugins: `build-logic/src/main/kotlin/*.gradle.kts` - Groovy convention plugins: `build-logic/src/main/groovy/*.gradle` - The project must apply **`kotlin-dsl`** (Kotlin) or **`groovy-gradle-plugin`** (Groovy). These plugins scan those source roots and compile each script into a `Plugin<Project>`. ## Id derivation The generated plugin's id is the **filename minus the build-script suffix**: | Filename | Plugin id | |---|---| | `java-conventions.gradle.kts` | `java-conventions` | | `com.acme.java-conventions.gradle.kts` | `com.acme.java-conventions` | The dotted prefix in the filename is the simplest, recommended way to give the plugin a namespaced id. ## Packages If you place the file in a package directory, e.g. `src/main/kotlin/com/acme/java-conventions.gradle.kts`, and add `package com.acme` at the top of the script, the **package is prepended** to the id: the plugin id becomes `com.acme.java-conventions`. So two routes lead to the same id — a dotted *filename* or a *package* + plain filename. Mixing them (dotted filename **and** a package) compounds the prefix and is a common confusion; pick one convention. ## Valid ids A plugin id must be a valid Gradle plugin id: dot-separated segments of alphanumerics, `-`, and `_`. Filenames that would produce an illegal id won't compile. Stick to lowercase, dotted, hyphen-separated names like `com.acme.kotlin-library`. ## Wiring for consumers For the ids to be visible to the main build, `build-logic` is usually included in `settings.gradle.kts`: ```kotlin pluginManagement { includeBuild("build-logic") } ``` (With `buildSrc`, the conventions are visible automatically — but the buildSrc-vs-build-logic decision is owned by a separate topic.) ## Gotchas 1. Wrong source root (`src/main/java` or root) → script ignored, plugin not generated. 2. Forgetting `kotlin-dsl` → no compilation, no plugin. 3. Expecting the package to be ignored — it's prepended to the id. 4. Using characters illegal in plugin ids in the filename. 5. Forgetting `includeBuild` in `pluginManagement`, so consumers can't resolve the id.
- If you put a file in `src/main/kotlin/com/acme/` with `package com.acme` AND name it `com.acme.foo.gradle.kts`, what id results?The package and the dotted filename both contribute, so you get a doubled prefix like `com.acme.com.acme.foo` — a classic mistake. Use either a dotted filename or a package, not both.
- What happens if the script is in `src/main/java` instead of `src/main/kotlin`?The `kotlin-dsl` plugin won't pick it up, so no plugin is generated and applying its expected id fails with 'plugin not found'.
saying these in an interview costs you the question
- Believing the package declaration is ignored for the id.
- Putting scripts in the wrong source root.
- Using filenames that aren't valid plugin ids.