Authoring Plugins, Tasks and Extensions
Writing build logic as real software: custom task types, plugins, DSL extensions, the lazy property API, worker concurrency, and structured diagnostics. Interviewers use this area to separate people who configure Gradle from people who extend it.
§on this pageshowhide
§explore
§questions
186 · 6 sectionsWhat does the @CacheableTask annotation do, and what is the difference between marking a task cacheable and the build cache simply being enabled?
basics
~10 s@CacheableTask on a task type opts that type into the build cache, so its outputs can be stored and reused. Enabling the build cache alone does nothing unless task types are marked cacheable.
What is a CommandLineArgumentProvider in Gradle, and why would you use one instead of just adding strings to a task's args?
basics
~10 sIt's a small object that supplies command-line arguments lazily via asArguments(). You register it on a task (e.g. JavaExec/Test) so the actual arguments are computed at execution time rather than hardcoded as plain strings.
What is DefaultTask and how do you create a custom task type by subclassing it?
basics
~10 sDefaultTask is Gradle's base class for tasks. You create a custom task type by subclassing it and adding one method annotated with @TaskAction, which holds the work the task runs when executed.
What does `dependsOn` do in Gradle, and how is a task dependency different from controlling the mere ordering of two tasks?
basics
~20 sdependsOn declares that one task requires another to run first; if you ask for task A, Gradle also runs its dependencies. A pure ordering hook only sequences tasks that are already scheduled — it never adds a task to the build.
What is the purpose of annotating task properties with @Input, @InputFile, and @OutputFile in a custom Gradle task?
basics
~10 sThey tell Gradle which properties are a task's inputs and outputs so Gradle can decide if the task is up-to-date and skip running it when nothing relevant changed.
How do you declare a plugin id for a custom Gradle plugin using the java-gradle-plugin plugin, and what is the role of implementationClass?
basics
~20 sApply the java-gradle-plugin plugin, then in the gradlePlugin { plugins { … } } block register a plugin entry with an id and an implementationClass — the fully-qualified name of your Plugin<Project> class that Gradle instantiates when that id is applied.
What is a precompiled script convention plugin in Gradle, and what problem does it solve?
basics
~10 sIt's a *.gradle.kts file placed in a build-logic project's source set that Gradle compiles into a plugin. You apply it by id to share common build configuration across many subprojects instead of copy-pasting it.
What is Gradle's ProjectBuilder and what do you use it for when developing a plugin?
basics
~10 sProjectBuilder creates a throwaway Project instance in a JVM unit test (ProjectBuilder.builder().build()), so you can apply your plugin and assert it wired up tasks, extensions or configurations — without running a real build.
What is the Plugin<Project> interface in Gradle, and what does the apply method do?
basics
~10 sPlugin<Project> is the interface a Gradle plugin implements. Its single apply(project) method runs when the plugin is applied and is where you configure the project: register tasks, add extensions, or apply other plugins.
What is a Settings plugin in Gradle, and how does it differ from a Project plugin?
basics
~10 sA Settings plugin implements Plugin<Settings> and is applied in settings.gradle(.kts). It configures the build as a whole (which projects exist, repositories, plugin resolution), unlike a Project plugin that configures one project's tasks and dependencies.
What does Property.convention(...) do on a Gradle lazy property, and how does it differ from calling set(...)?
basics
~10 sconvention(...) supplies a default value used only if nobody calls set(...). set(...) is an explicit assignment that overrides any convention. So convention = fallback default, set = the actual chosen value.
What is a Gradle DSL extension, and how do you register one from a plugin so users can configure your plugin in their build script?
basics
~10 sAn extension is an object added to a project that exposes a configuration block (DSL). A plugin registers it with project.extensions.create("myExt", MyExtension::class.java), then users configure it via a myExt { ... } block.
What is a NamedDomainObjectContainer in Gradle, and why would a plugin author expose one in their extension?
basics
~10 sIt's a Gradle collection of objects each identified by a unique name. Plugins expose one so users can declare multiple named instances in a DSL block, like sourceSets or configurations.
Your plugin defines an extension with a `Property<String>` called `greeting`. How do you connect that extension value to a task's input property so the task uses whatever the user sets in the build script?
basics
~10 sUse task.greeting.set(extension.greeting). This wires the task's Property to the extension's Property lazily, so the value is read later (at execution), not while configuring.
Why are modern Gradle extensions written as abstract classes with abstract Property<> / ListProperty<> getters, and who provides the implementations?
basics
~20 sYou declare the extension abstract with abstract Property/ListProperty getters and no bodies. Because Gradle instantiates the class via ObjectFactory, it generates a subclass that implements those getters with initialized, lazy property objects — you don't write boilerplate.
What are ListProperty, SetProperty and MapProperty in Gradle, and how do you create them on a task or extension?
basics
~10 sThey are lazy, collection-valued properties: ListProperty<T>, SetProperty<T>, MapProperty<K,V>. You create them via ObjectFactory (objects.listProperty(String::class.java)) and usually expose them as abstract getters on a task or extension.
What is a ConfigurableFileCollection in Gradle, and how do you create one in a plugin or task?
basics
~10 sA ConfigurableFileCollection is a mutable, lazily-evaluated set of files. You create one with project.objects.fileCollection() and populate it with from(...), so the actual files are resolved later, not at configuration time.
What is ProjectLayout in Gradle, and how do you use it to point at a file or directory under the build directory?
basics
~10 sProjectLayout (project.layout) gives lazy access to the project and build directories. You use layout.buildDirectory.file("name") or .dir("name") to point at outputs under build/ without resolving paths eagerly.
What does Provider.map do in Gradle, and why is it preferred over reading a provider's value at configuration time?
basics
~10 smap transforms a provider's value into a new provider using a function, without computing it now. The transform runs lazily only when the value is finally queried, so it stays deferred until execution time.
What is the ObjectFactory service in Gradle, and how do you obtain an instance of it?
basics
~10 sObjectFactory is a Gradle service that creates instances of model objects like Property, FileCollection, and custom managed types. You get it via @Inject in a constructor or through project.objects.
What is the Gradle Worker API, and why would a custom task use it instead of just running its work directly in the task action?
basics
~20 sThe Worker API lets a task hand units of work to Gradle's worker pool so they run in parallel. You inject WorkerExecutor, define a WorkAction, and submit work to a queue. It enables parallelism and isolation that a plain task action can't get.
How do you define and register a BuildService with parameters, and how are those parameters supplied?
basics
~10 sDefine a nested Params interface extending BuildServiceParameters with Property fields, then register with registerIfAbsent and set those Property values inside the configuration action.
What is a Gradle BuildService, and what problem does it solve?
basics
~10 sA BuildService is a shared, build-scoped object that holds state or resources (caches, connections) and can be safely shared across tasks, including tasks running in parallel.
The Gradle Worker API offers three isolation modes — noIsolation, classLoaderIsolation, and processIsolation. What does each one isolate, and how do they differ?
basics
~10 snoIsolation runs work in the Gradle JVM with the buildscript classpath. classLoaderIsolation runs it in the same JVM but under a separate classloader from a custom classpath. processIsolation runs it in a forked JVM.
What does the @ServiceReference annotation do on a Gradle task, and why is it preferable to manually wiring a build service?
basics
~10 s@ServiceReference marks an abstract Property<MyService> on a task so Gradle auto-injects a registered shared build service and automatically tracks it as a task dependency, so you don't call usesService() yourself.
What is the Gradle Problems Report HTML, where is it written, and when does Gradle generate it?
basics
~10 sIt is an aggregated HTML file at build/reports/problems/problems-report.html that lists all problems and deprecations Gradle and plugins reported during the build. Gradle generates it automatically when problems exist.
What is Gradle's Problems API and why would a plugin author report a structured problem instead of just throwing an exception or logging a warning?
basics
~20 sThe Problems API lets a plugin report build issues as structured data (an ID, a message, severity, location) instead of plain text. Gradle then surfaces them uniformly in the console, the HTML report, IDEs, and the Tooling API.
When reporting a structured problem with Gradle's Problems API, what severity levels can you assign via the ProblemSpec, and what does each one mean for the build?
basics
~20 sSeverity is set with spec.severity(...) using the Severity enum: WARNING, ERROR, and ADVICE. ERROR signals a real failure, WARNING a concern, and ADVICE a hint/suggestion. It classifies the problem; it does not by itself fail the build.
How does the Problems Report group entries, and what role does ProblemId (group + id) play in how problems surface to consumers?
basics
~20 sEach reported problem carries a ProblemId — a stable id plus a ProblemGroup. The report uses that grouping to cluster problems of the same kind under shared headings, so consumers see a tree instead of a flat list.
How do you obtain the Problems service inside a plugin or task, and why can't you just instantiate it?
basics
~10 sYou don't create it — Gradle injects it. Add a constructor parameter of type Problems annotated with @Inject on your Plugin or Task (using an abstract class), and Gradle's service registry supplies the instance.