What is the difference between the `Sync` task and the `Copy` task in Gradle, and when would you reach for `Sync`?
answer
- Sync extends Copy
- deletes stale destination files
- exact mirror
- preserve { include }
- never sync into a source dir
basics
~10 sSync copies like Copy but also DELETES anything in the destination that isn't in the source, leaving the target as an exact mirror. Copy only adds/overwrites; it never removes stale files.
solid answer
~40 s`Sync` is a subclass of `Copy`: it accepts the same `CopySpec` DSL (`from`, `into`, `include`/`exclude`, `rename`), but after copying it **removes any pre-existing files in the destination that the source no longer provides**. The result is that the destination becomes an exact mirror of the filtered source set. Use `Sync` when you want a clean, deterministic output directory — e.g. assembling a distribution/install image, a `node_modules`-style staging dir, or copying runtime dependencies into `build/libs`. Use plain `Copy` when you only want to add files without disturbing what's already there. A common gotcha: never point `Sync.into` at a directory that contains unrelated files (like a source dir or project root), because `Sync` will delete them. `Sync` also supports `preserve { include(...) }` to whitelist destination paths that should survive the cleanup.
code
kotlin · 6 linestasks.register<Sync>("stageDist") {
from("src/dist")
from(configurations.runtimeClasspath) { into("lib") }
into(layout.buildDirectory.dir("dist"))
preserve { include("data/**") }
}go deeper
Know Sync = Copy that also deletes extras so the target mirrors the source.
Explain Sync extends Copy, the delete-stale semantics, and a real use (staging a dist).
Discuss preserve, incrementality, and the destructive-target hazard with safe-directory conventions.
Set org guardrails: Sync targets must be dedicated build dirs; review destructive tasks in shared plugins.
## `Sync` = `Copy` + delete-stale `Sync` extends `Copy`. Everything you know about `Copy` — the `CopySpec` DSL (`from`, `into`, `include`, `exclude`, `rename`, `expand`, `eachFile`) — works identically. The *one* added behavior is the cleanup pass: **after the copy, any file already in the destination that does not correspond to a copied source file is deleted.** The net effect: the destination directory ends up being an *exact mirror* of the (filtered) source. This makes `Sync` the right tool for any "build me a clean staging directory" job. ### Typical uses - Staging an install/distribution image where leftover files from a previous build must not linger. - Copying the runtime classpath into one folder: ```kotlin tasks.register<Sync>("installLibs") { from(configurations.runtimeClasspath) into(layout.buildDirectory.dir("install/lib")) } ``` Run it once with 10 deps, remove a dep, run again — the removed jar is gone from `install/lib`. A plain `Copy` would leave the stale jar behind. ### `preserve` — protecting destination files Sometimes the destination legitimately contains files you generated by other means and must keep. `Sync` exposes a `preserve { ... }` spec: ```kotlin tasks.register<Sync>("stage") { from("src/dist") into(layout.buildDirectory.dir("stage")) preserve { include("logs/**") } } ``` Anything matching the `preserve` filter survives the cleanup. ### Danger zone Because `Sync` deletes, **pointing `into` at the wrong directory is destructive**. Never sync into a source folder, the project root, or any directory with hand-maintained content you didn't put there. Always target a dedicated `build/` subdirectory. ### Incrementality Like `Copy`, `Sync` is incremental and can be UP-TO-DATE: Gradle tracks the source as inputs and the whole destination directory as output.
- What does `preserve` do in a Sync task?It whitelists destination paths (by include/exclude patterns) that should NOT be deleted during the cleanup pass, even though they aren't in the source.
- Why is it risky to set Sync's `into` to your project's source directory?Sync deletes any destination file not provided by the source, so it could wipe out your hand-written source files. Always target a dedicated build subdirectory.
- Is Sync still incremental?Yes — it tracks the source as inputs and the destination as output, so an unchanged run is UP-TO-DATE.
Copy is like dragging files into a folder; Sync is like 'rsync --delete' — the target ends up identical to the source, extras removed.
saying these in an interview costs you the question
- Claiming Sync and Copy behave identically — the delete-stale pass is the whole point.
- Saying Sync only updates changed files — it also removes files absent from the source.