skip to content

Configurable File Collections

ConfigurableFileCollection from ObjectFactory, its from/setFrom/builtBy wiring, and using it as a managed @InputFiles property. Asked because an eagerly resolved FileCollection loses both laziness and the task dependencies it carried.

on this pageshow

questions

5

What is a ConfigurableFileCollection in Gradle, and how do you create one in a plugin or task?

level: juniorimportance: must knowfreq 55%

answer

  1. objects.fileCollection()
  2. lazy / live set of files
  3. from(...) accepts almost anything
  4. resolved on query, not declaration
  5. implements Iterable<File>

basics

~10 s

A 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.

solid answer

~30 s

A `ConfigurableFileCollection` is Gradle's mutable, lazy container for a set of files. Unlike a plain `FileCollection` you build eagerly with `project.files(...)`, you create a `ConfigurableFileCollection` via `project.objects.fileCollection()` (the `ObjectFactory`). You add sources with `from(...)`, which accepts almost anything resolvable to files — `File`, `String` paths, `Provider`s, other `FileCollection`s, even closures — and Gradle only resolves them when the collection is actually queried. This laziness lets a task wire up inputs whose locations aren't known yet at configuration time and keeps you compatible with the configuration cache. It implements `Iterable<File>`, so you can iterate it like a normal collection once resolved.

code

kotlin · 5 lines
kotlin
val sources: ConfigurableFileCollection = project.objects.fileCollection()
sources.from("src/main/resources")
sources.from(layout.buildDirectory.dir("generated"))
// resolution happens here, lazily:
sources.files.forEach { println(it) }

go deeper

for a junior

Know it's a lazy, mutable file set created via objects.fileCollection() and filled with from(...).

for a middle

Explain the laziness — files resolved on query — and why objects.fileCollection() is preferred over project.files().

for a senior

Tie it to configuration-cache safety and to using it as a managed @InputFiles property instead of an eager FileCollection.

for a principal

Frame conventions for plugin authors: standardize on ObjectFactory-created collections so plugins stay decoupled from Project and cache-compatible across a codebase.

## What it is A **`FileCollection`** in Gradle is a lazily-evaluated, *live* set of files — "live" meaning the actual `File` instances are computed only when you query the collection, not when you declare it. A **`ConfigurableFileCollection`** is the *mutable* subtype: you can keep adding sources to it after creation. ## Eager vs lazy creation - `project.files(...)` returns a `ConfigurableFileCollection` too, but you typically use it ad-hoc and it's tied to the `Project`. - `project.objects.fileCollection()` — via the **`ObjectFactory`** — is the preferred way inside plugins/tasks because it doesn't need a `Project` reference and plays well with managed types and the configuration cache. ## Populating it The key method is **`from(Object...)`**. It is extremely permissive about what you pass: - `File`, `Path`, `String` (relative to project dir) - a `Provider<T>` (e.g. `layout.buildDirectory.file("out.txt")`) - another `FileCollection` or `FileTree` - a `Callable`/closure that returns any of the above — this is how you defer resolution Because everything is resolved on query, you can call `from(someProvider)` before the provider has a value. ## Why laziness matters If you resolved file paths at configuration time (e.g. by calling `.get()` early), you'd break the **configuration cache** and force work even when the task won't run. A `ConfigurableFileCollection` defers all of that to execution time. ```kotlin val sources = project.objects.fileCollection() sources.from("src/main/resources") sources.from(layout.buildDirectory.dir("generated")) // nothing resolved yet — only when sources.files or iteration happens sources.forEach { println(it) } ``` ## It is iterable `ConfigurableFileCollection : FileCollection : Iterable<File>`, so once queried you can iterate, call `.files` (a `Set<File>`), `.singleFile`, `.isEmpty`, `.filter { }`, or combine with `+` / `-`.

  • What is the difference between project.files(...) and project.objects.fileCollection()?
    Both return a ConfigurableFileCollection, but objects.fileCollection() comes from the ObjectFactory, needs no Project reference, and is the recommended form inside managed types and configuration-cache-compatible plugins. project.files() is convenient but couples you to the Project.
  • When are the files actually resolved?
    Only when the collection is queried — iterated, .files / .singleFile read, or used as a task input during execution — not when from(...) is called.

saying these in an interview costs you the question

  • Calling it an immutable or eagerly-resolved snapshot of files.
  • Saying you must pass only File objects to from(...) (it accepts providers, strings, callables, etc.).

context

open as a page

What is the difference between from() and setFrom() on a ConfigurableFileCollection?

level: middleimportance: must knowfreq 50%

basics

~10 s

from(...) appends new sources to whatever is already there; setFrom(...) replaces all existing sources with exactly what you pass. Use from to accumulate, setFrom to reset.

open as a page

How do you expose a ConfigurableFileCollection as a managed @InputFiles property on a custom task instead of an eager FileCollection?

level: middleimportance: must knowfreq 48%

basics

~10 s

Declare an abstract getter returning ConfigurableFileCollection, annotated with @InputFiles. Gradle manages the instance for you, so you never create or assign it — callers just use from() to set sources.

open as a page

How does a ConfigurableFileCollection carry task dependencies, and when do you need builtBy()?

level: seniorimportance: should knowfreq 38%

basics

~20 s

A ConfigurableFileCollection tracks the tasks that produce its files. If you add a task output or a Provider that knows its producer, dependencies are inferred automatically. builtBy() is for the case where you add raw files whose producing task Gradle can't infer.

open as a page

What are the lazy .elements and .asFileTree views of a ConfigurableFileCollection, and when do you use each?

level: seniorimportance: should knowfreq 30%

basics

~10 s

.elements returns a Provider<Set<FileSystemLocation>> — a lazy view you can map/wire without resolving now. .asFileTree turns the collection into a FileTree so you can walk directory contents recursively and apply include/exclude patterns.

open as a page