skip to content

When would you reach for the `distribution` plugin to package arbitrary content instead of the `application` plugin, and how do they relate?

level: middleimportance: should knowfreq 35%

answer

  1. application applies distribution + java
  2. application => start scripts + classpath + run
  3. distribution alone = archive only, no launcher
  4. combine: app main + create(docs)
  5. raw Zip task = no installDist/lifecycle wiring

basics

~10 s

Use distribution when you just need to ship arbitrary files (docs, configs) as an archive with no runtime/launcher. The application plugin is for runnable JVM apps and is built on top of distribution.

solid answer

~40 s

The `application` plugin **applies** the `distribution` plugin internally and configures its `main` distribution to hold the app jar, runtime classpath, and generated start scripts (`bin/<app>` and `bin/<app>.bat`). So it gives you a *runnable* layout: `installDist`, `run`, `distZip`. The bare `distribution` plugin gives you the same archive machinery with **no application semantics** — no `mainClass`, no start scripts, no classpath assembly. You reach for `distribution` directly when the artifact isn't a runnable program: a documentation bundle, a set of config templates, a sample/data pack, SDK headers, or a side-car archive alongside your app. You can even apply both: keep `application` for the runnable `main` distribution and add extra named distributions (`distributions.create("docs")`) for non-code content. Choosing `distribution` avoids paying for launcher generation you don't want.

go deeper

for a junior

Knows application is for runnable apps and distribution is for arbitrary archives.

for a middle

Can articulate that application is built on distribution, what each pre-configures, and when to pick which.

for a senior

Can combine both for app + side-car archives and justify distribution over a raw Zip task by the conventions it adds.

for a principal

Defines the org packaging strategy: which artifacts ship as distributions, how docs/config bundles are standardized, and reproducibility across teams.

## Two plugins, one engine Both plugins produce archives via the same `distributions` container and `CopySpec` engine. The difference is **how much they pre-configure**. ### `application` plugin Applying `application`: 1. Applies the `java` and `distribution` plugins. 2. Configures the `main` distribution's `contents` to include: the project jar (`lib/`), the runtime dependencies (`lib/`), and OS start scripts (`bin/`). 3. Adds `run` (launch from build), `startScripts` (generate launchers), `installDist` (explode to `build/install`), and `distZip`/`distTar`. 4. Requires `application { mainClass.set(...) }`. So it's opinionated toward a **runnable JVM program**. ### `distribution` plugin Applying `distribution` alone: 1. Adds the `distributions` container with an empty `main`. 2. Adds `assembleDist`, `installDist`, and per-distribution `*DistZip`/`*DistTar`. 3. Configures **nothing** about contents — you declare everything via `contents { }`. No `mainClass`, no scripts, no classpath. Pure archive packaging. ### Decision guide | Need | Plugin | |---|---| | Runnable CLI/server with launcher scripts | `application` | | Docs/config/sample bundle, no executable | `distribution` | | Both a runnable app AND extra side-car archives | `application` + extra `distributions.create(...)` | | Fat/uber jar | Shadow plugin (separate concern) | ### Combining them ```kotlin plugins { application distribution // implied by application, but harmless } application { mainClass.set("com.acme.Main") } distributions { // 'main' already configured by the application plugin create("docs") { contents { from("src/docs") } } } ``` Now `distZip` ships the runnable app and `docsDistZip` ships the documentation — two independent archives from one build. ### Why not just use a Zip task? You *can* register a raw `Zip` task. The distribution plugin adds value: a named container, `installDist` (an exploded view for local testing), lifecycle wiring into `assemble`, and a consistent naming convention. For one-off archives a `Zip` task is fine; for a first-class shippable artifact, distributions are cleaner.

  • Can you have a runnable app and a docs-only archive in the same project?
    Yes. Apply `application` (which configures the `main` runnable distribution) and add `distributions.create("docs") { contents { ... } }`. You then get `distZip` for the app and `docsDistZip` for the docs — two independent archives.
  • What does the `distribution` plugin give you over a raw `Zip` task?
    A named distributions container, `installDist` for an exploded local-test view, automatic `*DistZip`/`*DistTar` task pairs, consistent archive naming with classifiers, and wiring into the `assemble`/`build` lifecycle. A raw `Zip` task is fine for one-offs but lacks these conventions.

saying these in an interview costs you the question

  • Saying the application plugin doesn't use distributions — it's built on the distribution plugin.
  • Using the application plugin and then fighting it to remove start scripts, when you really wanted the bare distribution plugin.

context