skip to content

Task Declaration & Registration

The ways a task comes into existence: lazy register versus eager create, the built-in task types Gradle ships, and plain ad-hoc tasks. Interviewers use this area to check whether you write builds that stay cheap to configure.

on this pageshow

explore

questions

page 1 of 2

What does the Gradle `init` task do, and how do you use it to scaffold a new project?

level: juniorimportance: must knowfreq 55%

answer

  1. build-init plugin task
  2. generates settings + build scripts
  3. creates the Gradle wrapper
  4. interactive prompts or flags
  5. run with system gradle once

basics

~20 s

gradle init is a built-in task from the build-init plugin that scaffolds a new Gradle project: it generates build/settings scripts, a sample source layout, and the Gradle wrapper, prompting you (or via flags) for project type, DSL, and test framework.

solid answer

~40 s

`gradle init` is the entry-point task of the bundled `build-init` plugin. Run from an empty (or existing) directory, it bootstraps a new build: it writes `settings.gradle(.kts)`, one or more `build.gradle(.kts)` scripts, a skeleton `src/main` + `src/test` layout, a `.gitignore`, and—critically—the **Gradle wrapper** (`gradlew`, `gradlew.bat`, `gradle/wrapper/*`) so collaborators don't need Gradle pre-installed. Interactively it asks for the project type (e.g. `java-application`, `kotlin-library`), the build DSL (Kotlin or Groovy), the test framework, and a project name. All of those can be supplied non-interactively as flags (`--type`, `--dsl`, `--test-framework`) for CI or scripting. Because you usually run it before Gradle is installed locally, you invoke the system `gradle` once, then switch to `./gradlew` thereafter.

code

bash · 12 lines
bash
# Interactive scaffold
gradle init

# Fully non-interactive (CI-friendly)
gradle init \
  --type java-application \
  --dsl kotlin \
  --test-framework junit-jupiter \
  --project-name myapp

# After init, always use the wrapper
./gradlew build

go deeper

for a junior

Know that gradle init scaffolds a new project and creates the wrapper; be able to run it interactively.

for a middle

Explain the flags (--type, --dsl, --test-framework) and the full set of generated artifacts including settings, build scripts, and version catalog.

for a senior

Discuss running it non-interactively in tooling, migrating from Maven, and why the wrapper guarantees reproducible builds.

for a principal

Frame init as a standardization lever—seeding org-wide conventions (DSL choice, version catalogs, test framework) consistently across new repos.

## What `init` is `init` is a task contributed by the **`build-init` plugin**, one of the plugins Gradle bundles into its distribution. You don't apply it in a build script—it's available from a system `gradle` install (or even an empty directory) so it can create a build *from scratch*. ## What it generates For a typical application type, `gradle init` produces: - `settings.gradle.kts` (or `.groovy`) declaring `rootProject.name` and included subprojects. - `build.gradle.kts` for each generated project/subproject with plugins, dependencies, and a configured test framework. - A source skeleton: `app/src/main/...` and `app/src/test/...` with a sample class and test. - The **Gradle wrapper**: `gradlew`, `gradlew.bat`, `gradle/wrapper/gradle-wrapper.jar`, and `gradle/wrapper/gradle-wrapper.properties`. This pins the Gradle version so everyone builds reproducibly. - A `.gitignore` and (for newer types) a `gradle/libs.versions.toml` version catalog. ## Interactive vs non-interactive Run with no arguments, `init` *interactively prompts* for: type, implementation language, build DSL, test framework, project name, and source package. Each prompt can be pre-answered with a flag so the task is fully scriptable: ```bash gradle init --type java-application --dsl kotlin --test-framework junit-jupiter --project-name myapp ``` ## Why the wrapper matters Because `init` is often the *first* Gradle command in a project's life, generating the wrapper means the next person who clones the repo runs `./gradlew build` with the exact pinned Gradle version—no manual install, no version drift. After `init`, you stop using the system `gradle` and use `./gradlew`. ## Detecting existing projects If you run `init` in a directory that already contains a Maven `pom.xml`, the plugin can migrate it (`--type pom`). In an empty directory with no flags it asks what to build.

  • Why does `init` generate the Gradle wrapper?
    So the project pins its Gradle version and teammates/CI can build with `./gradlew` without any local Gradle install, guaranteeing a reproducible version.
  • Do you apply the build-init plugin in your build script?
    No. It's bundled into the Gradle distribution and exposed automatically by a system `gradle` install (or from an empty directory), so its `init` task is always available.

saying these in an interview costs you the question

  • Claiming you must add `build-init` to the plugins block—it's bundled, not applied.
  • Saying `init` only writes a build script and forgetting it also generates the wrapper and source skeleton.

context

open as a page

What is Gradle's Configuration Avoidance API, and what problem does it solve?

level: juniorimportance: must knowfreq 60%

basics

~10 s

It's a set of lazy task APIs (TaskProvider, tasks.named, configureEach) that let Gradle skip creating and configuring tasks you don't run, cutting configuration-time cost.

open as a page

How do you define a task in Gradle that copies files from one directory into another, and what are the core DSL elements you use?

level: juniorimportance: must knowfreq 65%

basics

~10 s

Register a task of type Copy and configure from (source) and into (destination). Gradle copies the matched files into the target directory when the task runs.

open as a page

What is the difference between doFirst and doLast on a task, and in what order do multiple actions run?

level: juniorimportance: must knowfreq 60%

basics

~10 s

doLast adds an action to the end of the task's action list; doFirst adds one to the front. Both run in the execution phase. If you call doFirst twice, the later one runs first.

open as a page

What is an ad-hoc task in Gradle, and how do you define one?

level: juniorimportance: must knowfreq 70%

basics

~10 s

An ad-hoc task is an untyped task of type DefaultTask whose behavior you add inline with doLast { ... }. You register it with tasks.register("name") and put the action in the closure.

open as a page

How do you select an existing task by name in a Gradle build script, and why is tasks.named() preferred over tasks.getByName()?

level: juniorimportance: must knowfreq 70%

basics

~10 s

Use tasks.named('compileJava') to get a lazy reference. It is preferred over getByName() because named() doesn't force the task to be configured immediately — configuration runs only if the task is actually needed.

open as a page

What is the difference between tasks.register and tasks.create in Gradle, and which should you prefer?

level: juniorimportance: must knowfreq 70%

basics

~10 s

tasks.create builds the task eagerly and runs its configuration immediately. tasks.register is lazy: it only registers the task and runs configuration if/when the task is actually needed. Prefer register.

open as a page

How do you declare a task in Gradle that packages a set of files into a Zip archive, and what are the key properties you configure on it?

level: juniorimportance: must knowfreq 55%

basics

~10 s

Register a task of type Zip, tell it which files to include with from(...), and set archiveFileName plus destinationDirectory to control the output file name and folder.

open as a page

What does the `--type` flag control in `gradle init`, and what happens if you omit it?

level: middleimportance: must knowfreq 45%

basics

~10 s

--type selects the project template to scaffold—e.g. java-application, kotlin-library, java-library, basic. It determines the plugins, source layout, and sample code generated. Omitting it makes init prompt interactively (or infer from an existing pom.xml).

open as a page

Why does `gradle init` also generate the Gradle wrapper, and what files make it up?

level: middleimportance: must knowfreq 42%

basics

~10 s

init generates the wrapper so the new project pins a specific Gradle version everyone uses via ./gradlew, without installing Gradle manually. The wrapper is four files: gradlew, gradlew.bat, gradle/wrapper/gradle-wrapper.jar, and gradle/wrapper/gradle-wrapper.properties.

open as a page

Why prefer configureEach over all (or the eager withType closure) when configuring many tasks?

level: middleimportance: must knowfreq 55%

basics

~10 s

all and the withType { } closure realize every matching task immediately. configureEach defers configuration so each task is only configured when (and if) it's realized.

open as a page

What is the difference between the `Sync` task and the `Copy` task in Gradle, and when would you reach for `Sync`?

level: middleimportance: must knowfreq 55%

basics

~10 s

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

open as a page

An ad-hoc task prints a value every single build even when you run an unrelated task. What is going on and how do you fix it?

level: middleimportance: must knowfreq 50%

basics

~20 s

The print is outside doLast, so it runs in the configuration phase, which executes every build for all projects. Move the side-effecting code inside doLast { ... } so it only runs when the task executes.

open as a page

Explain tasks.withType<Test>().configureEach { } — what does it do, and why use configureEach instead of all() or each()?

level: middleimportance: must knowfreq 60%

basics

~10 s

withType<Test>() selects all tasks of type Test, and configureEach applies the block to each — both existing and future ones — lazily. configureEach defers configuration; all()/each() would eagerly realize every matching task.

open as a page

You used tasks.register to keep a task lazy, but it still gets configured on every build. What kinds of code force a registered task to be realized?

level: middleimportance: must knowfreq 55%

basics

~10 s

Eager APIs force realization: tasks.getByName, tasks.create, tasks.all {}, iterating the task container, or calling .get() on a provider. Any of these realizes lazy tasks, undoing the benefit of register.

open as a page

How do you declare an Exec task to run an external command, and what are commandLine, args, and workingDir used for?

level: middleimportance: must knowfreq 45%

basics

~10 s

Register a task of type Exec and set commandLine to the executable plus its arguments. workingDir sets the directory to run in; args lets you set arguments separately from the executable.

open as a page

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%

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

open as a page

How do you register a typed task (e.g. a Zip task) lazily in both the Kotlin and Groovy DSL, and what does the 'by registering' syntax do?

level: juniorimportance: should knowfreq 40%

basics

~20 s

Pass the type as a second argument: tasks.register("zipIt", Zip::class) { } in Kotlin, or tasks.register('zipIt', Zip) { } in Groovy. 'by registering' is Kotlin delegate sugar that registers and binds a val to the provider.

open as a page

What does `--dsl` control in `gradle init`, and how would you decide between `kotlin` and `groovy`?

level: middleimportance: should knowfreq 40%

basics

~10 s

--dsl selects the build-script language for the generated scripts: kotlin produces *.gradle.kts files, groovy produces *.gradle files. Kotlin DSL gives type-safe, IDE-friendly scripts and is now the recommended default.

open as a page

How does `--test-framework` work in `gradle init`, and which frameworks are available?

level: middleimportance: should knowfreq 35%

basics

~10 s

--test-framework picks the testing library wired into the generated build and sample test—e.g. junit (JUnit 4), junit-jupiter (JUnit 5), testng, spock (Groovy), or kotlintest. It adds the right dependencies and configures tasks.test (e.g. useJUnitPlatform()).

open as a page

When configuring an existing task, why use tasks.named over tasks.getByName?

level: middleimportance: should knowfreq 45%

basics

~10 s

tasks.getByName realizes the task right away. tasks.named returns a TaskProvider and defers configuration until the task is actually realized, preserving configuration avoidance.

open as a page

Explain how `rename`, `expand`, `filter`, and `eachFile` work inside a Copy task's CopySpec, and when you'd use each.

level: middleimportance: should knowfreq 40%

basics

~10 s

rename changes file names (regex/closure), expand substitutes ${token} placeholders in text, filter transforms content line-by-line, and eachFile gives a per-file hook to tweak path/permissions or exclude files.

open as a page

How do you set the group, description, and dependsOn of an ad-hoc task, and what does each one do?

level: middleimportance: should knowfreq 55%

basics

~10 s

Inside the register block set group (the category in gradle tasks), description (the help text), and call dependsOn(...) to declare tasks that must run before this one. All three are properties on every task.

open as a page

When would you use tasks.matching { } to select tasks, and what are its trade-offs compared to withType()?

level: middleimportance: should knowfreq 40%

basics

~20 s

tasks.matching { } returns a live collection of tasks satisfying an arbitrary predicate — e.g. by name prefix. Use it when a type filter isn't enough. The trade-off: its predicate is less configuration-avoidance-friendly than withType's pure type filter.

open as a page

What is the benefit of the typed form tasks.named<JavaCompile>('compileJava') over the untyped tasks.named('compileJava'), and what happens if the type is wrong?

level: middleimportance: should knowfreq 35%

basics

~10 s

The typed form returns a TaskProvider<JavaCompile>, giving statically-typed access to JavaCompile properties inside the block — no cast needed. If the actual task isn't that type, Gradle fails when the task is realized.

open as a page

How do you reference and wire a task declared with tasks.register without realizing it? Show how to use the returned TaskProvider.

level: middleimportance: should knowfreq 45%

basics

~10 s

register returns a TaskProvider. Pass the provider itself to dependsOn or inputs — Gradle resolves it lazily. Use provider.configure { } to add config, and flatMap to read its outputs without calling get().

open as a page

How does the Tar task differ from the Zip task, and how do you produce a gzip-compressed tarball (.tar.gz)?

level: middleimportance: should knowfreq 35%

basics

~10 s

Tar is the same kind of archive task as Zip but produces a .tar. Set its compression property to Compression.GZIP and give it a .tar.gz extension to get a compressed tarball.

open as a page

What operations force a lazily-registered task to be realized, and how do you avoid accidentally triggering them?

level: seniorimportance: should knowfreq 40%

basics

~10 s

Calling get() on a TaskProvider, getByName/create, tasks.all/withType-closure, iterating the task container, or requesting the task on the CLI all realize it. Wire dependencies with providers and use named/configureEach to stay lazy.

open as a page

When assembling a complex output directory (e.g. an install image with libs, configs, and scripts in different subfolders), how do you structure Copy/Sync tasks, and what laziness and correctness pitfalls should you watch for?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Use one Sync/Copy task with nested from(...) { into("subdir") } child CopySpecs to fan files into subfolders. Wire inputs via Providers/configurations so they stay lazy, and target a dedicated build dir so Sync's delete is safe.

open as a page

When would you choose a typed (or custom) task over an ad-hoc doLast task, and what do you lose by staying ad-hoc?

level: seniorimportance: should knowfreq 45%

basics

~10 s

Use a typed/custom task when logic is reused, needs declared inputs/outputs for up-to-date checks and caching, or needs unit testing. Ad-hoc doLast tasks are fine for tiny one-off glue but get none of that.

open as a page

showing 1–30 of 36