What do @Internal and @Optional do on task properties, and when do you reach for them?
answer
- @Internal = exclude from tracking
- @Optional = nullable tracked property
- @Optional is a modifier, never alone
- @Internal silences validation warning
- don't @Internal a real input
basics
~10 s@Internal marks a property as deliberately NOT part of inputs/outputs, so it's excluded from up-to-date checks. @Optional says an input/output property is allowed to be unset/null without failing validation.
solid answer
~40 s`@Internal` declares that a property is intentionally *not* a tracked input or output — useful for services, loggers, derived values, or anything that doesn't affect the result. It silences Gradle's property-validation warning ('property X is not annotated') and keeps the fingerprint clean. `@Optional` is a *modifier* you stack on an input/output annotation (e.g. `@Optional @InputFile`) to say the property may be absent/null. Without it, an `@InputFile` whose value is unset fails validation; with it, an unset value simply contributes nothing to the fingerprint. They solve different problems: `@Internal` = 'ignore this for incrementality'; `@Optional` = 'this tracked property might legitimately have no value'. A frequent mistake is using `@Internal` to suppress a warning on something that actually *does* affect output — that reintroduces the stale-output bug `@Internal` looks like it fixes.
code
kotlin · 8 linesabstract class DeployTask : DefaultTask() {
@get:Input abstract val env: Property<String>
@get:Optional
@get:InputFile abstract val overrides: RegularFileProperty // may be unset
@get:Internal abstract val clock: Property<Clock> // not tracked
}go deeper
Know that @Internal excludes a property from up-to-date checks and @Optional allows an input/output to be unset.
Explain the validation warning @Internal resolves and that @Optional is a modifier paired with another annotation.
Reason about the correctness risk of mis-marking a real input as @Internal and how to audit task types for it.
Define review guidance that every property be deliberately classified; treat unjustified @Internal as a build-correctness defect.
## @Internal — explicit exclusion Every property on a task type should be classified. Gradle's validation flags any public getter that is neither an input, an output, nor `@Internal`. `@Internal` is how you say: *'this property exists but does not influence the task's result, so do not fingerprint it.'* Typical `@Internal` candidates: - injected services / `BuildService` handles - a `Logger` - derived/convenience accessors computed from other inputs - things like a temporary working directory you don't want to track ```kotlin @get:Internal abstract val httpClient: Property<HttpClient> ``` If you `@Internal` something that *does* affect output, the task wrongly stays UP-TO-DATE — the same class of bug as forgetting an annotation entirely. ## @Optional — nullable tracked properties By default a declared input/output must have a value. An unset `@InputFile`, for instance, fails validation with 'does not have a configured value'. `@Optional` relaxes that: ```kotlin @get:Optional @get:InputFile abstract val overrideConfig: RegularFileProperty ``` Now `overrideConfig` may be left unset; when unset it simply doesn't contribute to the fingerprint, and when set it's tracked normally. `@Optional` is a *combinable modifier* — it does nothing on its own and is always paired with an input/output annotation. ## Side-by-side | | @Internal | @Optional | |---|---|---| | Role | exclude from tracking | allow null/unset on a tracked property | | Used alone? | yes | no (modifier) | | Affects fingerprint? | removes property entirely | property tracked only when present | ## Mental model - Reach for `@Internal` when the answer to 'does changing this change my output?' is *no*. - Reach for `@Optional` when the answer is *yes, but it's allowed to be absent*.
- Can @Optional be used without an input/output annotation?No. @Optional is a modifier with no meaning on its own; it must accompany an annotation like @InputFile, @InputDirectory, or @OutputFile to relax that property's required-value rule.
- What is the risk of over-using @Internal to clear validation warnings?If you mark a property @Internal that actually influences the output, Gradle stops fingerprinting it and the task can stay UP-TO-DATE despite a meaningful change — a silent stale-output bug masquerading as a clean build.
saying these in an interview costs you the question
- Saying @Internal and @Optional are interchangeable — one excludes tracking, the other relaxes a tracked property's nullability.
- Using @Internal as a generic 'make the warning go away' switch regardless of whether the property affects output.