The Output Directory

Mill puts all its output in the top-level out/ folder.

Structure of the out/ Directory

The out/ folder contains all the generated files & metadata for your build. It holds some files needed to manage Mill’s longer running server instances (out/mill-server/*) as well as a directory and file structure resembling the project’s module structure.

Example of the out/ directory after running mill main.compile
out/
├── main/   (1)
│   ├── allScalacOptions.json
│   ├── allSourceFiles.json
│   ├── allSources.json
│   ├── compile.dest/  (2)
│   ├── compile.json
│   ├── compile.log  (3)
│   ├── compileClasspath.json
│   ├── compileIvyDeps.json
│   ├── enablePluginScalacOptions.json
│   ├── generatedSources.json
│   ├── ivyDeps.json
│   ├── javacOptions.json
│   ├── mandatoryIvyDeps.json
│   ├── mandatoryIvyDeps.super/  (4)
│   ├── mandatoryScalacOptions.json
│   ├── platformSuffix.json
│   ├── resolvedIvyDeps.json
│   ├── resolvedIvyDeps.log  (3)
│   ├── resources.json
│   ├── scalaCompilerClasspath.json
│   ├── scalaLibraryIvyDeps.json
│   ├── scalaOrganization.json
│   ├── scalaVersion.json
│   ├── scalacOptions.json
│   ├── scalacOptions.super/  (4)
│   ├── scalacPluginClasspath.json
│   ├── scalacPluginIvyDeps.json
│   ├── scalacPluginIvyDeps.super/  (4)
│   ├── sources.json
│   ├── transitiveCompileIvyDeps.json
│   ├── transitiveIvyDeps.json
│   ├── transitiveLocalClasspath.json
│   ├── unmanagedClasspath.json
│   └── upstreamCompileOutput.json
├── mill-profile.json
└── mill-server/VpZubuAK6LQHHN+3ojh1LsTZqWY=-1/
1 The main directory contains all files associated with tasks and submodules of the main module.
2 The compile task has tried to access its scratch space via Task.dest. Here you will find the actual compile results.
3 Two tasks printed something out while they ran. You can find these outputs in the *.log files.
4 Three tasks are overridden but re-use the result of their super-tasks in some way. You can find these result under the *.super/ path.

Task Metadata and Cached Files

Each named task (Target or Command) that is run has a representation in the out/ directory structure.

The module structure is reflected in the directories, so that each module of your project has a uniquely associated subdirectory under the out/ directory.

Each task is associated with one or multiple files and directories under its module directory. The following files can be found for a task foo:

foo.json

the cache-key and JSON-serialized return-value of the Task/Command. The return-value can also be retrieved via mill show foo.compile. Binary blobs are typically not included in foo.json, and instead stored as separate binary files in foo.dest/ which are then referenced by foo.json via PathRef references.

foo.dest/

optional, a path for the Task to use either as a scratch space, or to place generated files that are returned using PathRef references. A Task should only output files within its own given foo.dest/ folder (available as Task.dest) to avoid conflicting with another Task, but can name files within foo.dest/ arbitrarily.

foo.log

optional, the stdout/stderr of the Task. This is also streamed to the console during evaluation.

foo.super/

optional, holds task metadata for overridden tasks, so whenever you use a super.foo() in your foo task, you will find the metadata of the inherited task(s) under this directory.

The out/ folder is intentionally kept simple and user-readable. If your build is not behaving as you would expect, feel free to poke around the various foo.dest/ folders to see what files are being created, or the foo.json files to see what is being returned by a particular task. You can also simply delete folders within out/ if you want to force portions of your project to be rebuilt, e.g. by deleting the out/main/ or out/main/compile.* folders, but we strongly encourage you to use the clean command instead.

Cleaning some task state by manually deleting files under out/ may be convenient, but you need to be careful to always delete the foo.json file whenever you delete a foo.dest/ or foo.super/. Otherwise, you risk running into hard to diagnose issues later.

Instead, you should always give the clean command a try before manually deleting some file under out/.

Other files in the out/ directory

There are also top-level build-related files in the out/ folder, prefixed as mill-*.

mill-profile.json

Probably the most useful file for you. It logs the tasks run and time taken for the last Mill command you executed. This is very useful if Mill is being unexpectedly slow, and you want to find out exactly what tasks are being run.

mill-chrome-profile.json

This file is only written if you run Mill in parallel mode, e.g. mill --jobs 4. This file can be opened in Google Chrome with the built-in tracing: protocol even while Mill is still running, so you get a nice chart of what’s going on in parallel.

mill-server/*

Each Mill server instance needs to keep some temporary files in one of these directories. Deleting it will also terminate the associated server instance, if it is still running.

Using another location than the out/ directory

The default location for Mill’s output directory is out/ under the project workspace. If you’d rather use another location than out/, that lives in a faster or a writable filesystem for example, you can change the output directory via the MILL_OUTPUT_DIR environment variable.

build.mill (download, browse)
package build

import mill._

object foo extends Module {
  def printDest = Task {
    println(T.dest)
  }
}
> MILL_OUTPUT_DIR=build-stuff/working-dir ./mill foo.printDest
...
.../build-stuff/working-dir/foo/printDest.dest