skip to content

How do you delete files or directories in a Gradle build, and how does the built-in `clean` task relate to this?

level: juniorimportance: should knowfreq 45%

answer

  1. Delete task type
  2. delete(...) accepts paths/FileCollections
  3. clean = Delete of buildDirectory
  4. base plugin contributes clean
  5. followSymlinks
  6. not UP-TO-DATE

basics

~10 s

Register a Delete task and list paths via delete(...). The base plugin's clean task is just a Delete that removes the build directory (layout.buildDirectory).

solid answer

~40 s

Gradle has a built-in `Delete` task type. You configure it with `delete(...)`, which accepts file paths, directories, `FileCollection`s, or closures resolving to them. When the task runs it recursively deletes those targets. The familiar `clean` task contributed by the `base` plugin (and therefore the Java/JVM plugins) is simply a `Delete` task wired to remove `layout.buildDirectory`. For one-off imperative deletes inside another task's action you can use `project.delete(...)`, but for a declared, tracked clean step prefer a real `Delete` task. `Delete` also supports `followSymlinks(true)` to delete the link targets rather than just the symlinks. Because deletion has no meaningful 'output' to snapshot, `Delete` tasks generally always run (they aren't UP-TO-DATE the way Copy is).

code

kotlin · 5 lines
kotlin
tasks.register<Delete>("cleanTemp") {
    delete(layout.buildDirectory.dir("tmp"))
    delete(fileTree("logs") { include("**/*.log") })
    followSymlinks = false
}

go deeper

for a junior

Name the Delete task, delete(...), and that clean removes the build dir.

for a middle

Explain base-plugin origin of clean, imperative project.delete, and the no-UP-TO-DATE caveat.

for a senior

Discuss followSymlinks safety, composing custom clean tasks, and wiring them into clean.

for a principal

Standardize clean conventions and guard against destructive deletes in shared build logic.

## The `Delete` task type `Delete` is Gradle's built-in task for removing files and directories. Its core method is `delete(...)`, which is flexible about what you pass: - a `String`/`File` path, - a directory (deleted recursively), - a `FileCollection` or `FileTree`, - a `Provider`/closure that lazily resolves to any of the above. ```kotlin tasks.register<Delete>("cleanReports") { delete(layout.buildDirectory.dir("reports")) delete("out/tmp") } ``` ### The `clean` task When you apply the `base` plugin — which the `java`, `application`, and most JVM plugins pull in transitively — you automatically get a `clean` task. It is nothing more than a `Delete` task pre-configured to delete the project's build directory: ```kotlin // effectively what base contributes tasks.register<Delete>("clean") { delete(layout.buildDirectory) } ``` So `./gradlew clean` wipes `build/`. You can register additional `Delete` tasks for finer-grained cleanups and make `clean` depend on them if you want them swept too. ### Imperative `project.delete(...)` Inside a task action you can call `project.delete(...)` to delete immediately. This is fine for transient scratch files, but a declared `Delete` task is clearer and shows up in the task graph. ### `followSymlinks` By default `Delete` removes a symlink itself, not what it points to. `followSymlinks = true` makes it delete the link's target contents — use with care. ### Incrementality caveat A `Delete` task has nothing useful to snapshot as an output (the desired state is 'absent'), so Gradle does not mark it UP-TO-DATE; it typically runs every time it's invoked. That's expected for a destructive cleanup step.

  • Which plugin contributes the standard `clean` task?
    The `base` plugin, which the `java`/JVM plugins apply transitively. `clean` is a `Delete` task targeting `layout.buildDirectory`.
  • Why isn't a `Delete` task usually UP-TO-DATE?
    Its goal state is 'files absent', which Gradle can't snapshot as a positive output, so there's nothing to compare against — it just runs.

saying these in an interview costs you the question

  • Thinking `clean` is special magic — it's an ordinary `Delete` task on `build/`.
  • Assuming `Delete` skips when nothing changed; it generally runs every time.

context