skip to content

Authoring Task Types

Writing your own task class: the action method, annotated inputs and outputs, normalization, incremental execution, cacheability, and dependency wiring. Interviewers ask because a well-authored task type is what makes a build both fast and correct.

on this pageshow

questions

page 2 of 2

What does InputChanges.isIncremental mean, and how should an incremental task behave when it is false?

level: seniorimportance: should knowfreq 35%

basics

~20 s

isIncremental is true only when Gradle can give a reliable per-file delta. When false (first run, missing outputs, a non-@Incremental input changed), getFileChanges reports every file as ADDED, so your action effectively performs a full rebuild.

open as a page

What are the main correctness pitfalls when authoring an incremental task, and how do you avoid them?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Common pitfalls: forgetting @Incremental on the queried property, not handling REMOVED, assuming you're always on an incremental run, deriving outputs non-deterministically, and querying a property you didn't mark @Incremental. Avoid them with deterministic input→output mapping and a full-rebuild-safe ADDED branch.

open as a page

Where must input/output annotations be placed on a task class, and how does Gradle's property validation enforce correct declarations?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Annotations go on the property getter (in Kotlin, use @get:Input etc.). Gradle's property validation checks every public getter is classified as an input, output, or @Internal, and warns (or fails) on untracked or conflicting properties.

open as a page

How do @OutputFile and @OutputDirectory participate in up-to-date checks, and why does declaring outputs matter beyond just naming the result?

level: seniorimportance: should knowfreq 40%

basics

~10 s

@OutputFile/@OutputDirectory tell Gradle what a task produces. Gradle fingerprints outputs too, so it detects manual deletion or tampering and reruns. Declared outputs also let Gradle wire task dependencies and clean stale outputs.

open as a page

When would you choose @PathSensitive(NAME_ONLY) or NONE over RELATIVE for a task input? Give a concrete correctness consideration.

level: seniorimportance: should knowfreq 28%

basics

~20 s

Use NONE when only file content matters and location is irrelevant (e.g. a config blob). Use NAME_ONLY when the filename is significant but its directory isn't. Both are looser than RELATIVE, giving more cache hits — but only if the tool truly ignores the dropped path info.

open as a page

Beyond declaring inputs, what makes a task's outputs safe to cache, and how would you make a task that currently produces non-reproducible outputs cacheable?

level: principalimportance: should knowfreq 28%

basics

~20 s

Outputs must be reproducible: the same inputs must always yield the same bytes, with no timestamps, absolute paths, or randomness baked in. Make archives reproducible (fixed timestamps, sorted entries) and remove machine-specific data before marking the task cacheable.

open as a page

Your custom task uses @InputFiles for a jar classpath, and the build cache never hits across CI agents. Walk through diagnosing and fixing the input normalization.

level: principalimportance: should knowfreq 22%

basics

~20 s

Plain @InputFiles defaults to ABSOLUTE path sensitivity and full byte content, so jar timestamps and agent paths bust the fingerprint. Switch the property to @Classpath (or @CompileClasspath for compile inputs) so paths are ignored and jars are normalized, making the fingerprint portable.

open as a page

Can a custom task have multiple @TaskAction methods, and how do task actions and doFirst/doLast relate?

level: middleimportance: nice to knowfreq 30%

basics

~10 s

Yes, a task can have several @TaskAction methods; Gradle runs them in declaration order. doFirst and doLast add extra actions that run before and after the @TaskAction methods on the task's action list.

open as a page

How do you supply dynamic, cacheable compiler arguments to a JavaCompile task using a CommandLineArgumentProvider, and how does it differ from options.compilerArgs?

level: seniorimportance: nice to knowfreq 18%

basics

~10 s

Add a CommandLineArgumentProvider to JavaCompile's options.compilerArgumentProviders. Like raw options.compilerArgs the strings reach javac, but the provider lets you annotate underlying file/value inputs so up-to-date checks and the build cache stay correct.

open as a page

What is @ReplacedBy used for, and why can't you just rename an input/output property and replace its annotation?

level: seniorimportance: nice to knowfreq 12%

basics

~20 s

@ReplacedBy marks a deprecated getter that has been superseded by a new property, telling Gradle the old getter is NOT an input/output to track. It avoids double-counting the same value during a backward-compatible API migration on a task type.

open as a page

showing 31–40 of 40