skip to content

What is executableDir in the Application plugin, and how does it change the location of the start scripts within an install?

level: seniorimportance: should knowfreq 25%

answer

  1. relative script dir, default 'bin'
  2. moves scripts not lib/
  3. app home resolved relatively
  4. offset baked at generation
  5. match downstream packaging

basics

~20 s

executableDir is the relative path inside the distribution where the launcher scripts are placed; it defaults to "bin". Setting it (e.g. "runtime/bin") moves the scripts there, while the scripts still resolve the app home relative to their own location.

solid answer

~40 s

`executableDir` is an Application-plugin property (mirrored onto the `CreateStartScripts` task) that controls **where, relative to the install root, the start scripts live**. By default it is `"bin"`, giving the familiar `bin/<name>` layout. If you set `application.executableDir = "runtime/bin"`, the launchers end up at `runtime/bin/<name>` inside `build/install/<name>/`, while `lib/` stays at the root. The generated scripts compute the application home relative to their own location, so they keep working even when nested deeper — the script knows how many directories up the install root is. You'd change `executableDir` to match a downstream packaging convention (e.g., an OS package that expects executables under a specific subdirectory, or to coexist with other tooling). It's purely about script placement; it does not move `lib/` or rename anything.

code

kotlin · 6 lines
kotlin
application {
    mainClass.set("com.acme.Main")
    executableDir = "runtime/bin"
}
// build/install/myapp/runtime/bin/myapp
// build/install/myapp/lib/...   (lib stays at root)

go deeper

for a junior

Know executableDir defaults to 'bin' and sets where the scripts go.

for a middle

Explain it's a relative path within the dist, moves only the scripts, and lib/ stays at the root.

for a senior

Explain why the launcher still works (relative APP_HOME resolution, offset baked at generation) and realistic reasons to change it (downstream packaging layout).

for a principal

Align executableDir with org-wide container/OS-package conventions so all services share a predictable runtime layout.

## The property `executableDir` is exposed on the `application { }` extension and propagated to the `startScripts` (`CreateStartScripts`) task. It specifies the **relative directory, inside the distribution image, where the launcher scripts are written**. - **Default:** `"bin"` → scripts at `<install>/bin/<name>` and `<install>/bin/<name>.bat`. - **Custom:** e.g. `"runtime/bin"` → scripts at `<install>/runtime/bin/<name>`. ## What it does and doesn't move It only relocates the **scripts**. The `lib/` directory (jars) stays at the install root regardless. So with a custom `executableDir` you get: ``` build/install/myapp/ ├── runtime/ │ └── bin/ │ ├── myapp │ └── myapp.bat └── lib/ └── ...jars... ``` ## Why the app still launches The generated start scripts don't hardcode an absolute path. At runtime they resolve their **own** location and then compute `APP_HOME` by walking up the right number of parent directories. The number of `..` levels is derived from `executableDir` at generation time, so moving the scripts deeper keeps the classpath (which points at `<APP_HOME>/lib`) correct. This is why you must change `executableDir` through the plugin rather than just manually moving the file — Gradle bakes the correct relative offset into the script. ## How to set it ```kotlin application { applicationName = "myapp" mainClass.set("com.acme.Main") executableDir = "runtime/bin" } ``` or on the task directly: ```kotlin tasks.named<CreateStartScripts>("startScripts") { executableDir = "runtime/bin" } ``` ## When you'd use it - Matching an **OS-package or container layout** that expects launchers under a particular path. - Keeping the top of the install clean (e.g., separating runtime entry points from config you add via the distribution CopySpec). - Coexisting with sidecar scripts or wrappers placed elsewhere. ## Caveat Because the offset is baked into the script, **do not** manually move the generated launcher after the fact — set `executableDir` so Gradle computes the correct app-home resolution.

  • Does executableDir move the lib/ directory too?
    No — only the start scripts are relocated; lib/ remains at the install root.
  • Why shouldn't you just move the generated script manually instead of setting executableDir?
    The script bakes in the number of parent directories up to APP_HOME at generation time; set executableDir so Gradle computes the correct relative offset and the lib/ classpath still resolves.
  • What is the default value of executableDir?
    "bin", which yields the conventional bin/<name> location.

saying these in an interview costs you the question

  • Thinking executableDir moves or renames lib/ — it only affects where the scripts go.
  • Believing you can manually relocate the launcher without changing executableDir — the relative APP_HOME offset would break.

context