skip to content

What does it mean to register an artifact transform in Gradle, and what do `from` and `to` describe?

level: middleimportance: must knowfreq 45%

answer

  1. dependencies.registerTransform(Type) { }
  2. from = inputs, to = outputs
  3. attributes describe artifact shape
  4. declarative, lazy, cached
  5. variant-matching inserts the rule

basics

~10 s

You call dependencies.registerTransform(MyTransform) { ... } and declare from.attribute(...) and to.attribute(...). Gradle uses those attributes to know which artifacts the transform can convert and what it produces.

solid answer

~40 s

Registering a transform tells Gradle there is a rule that can convert an artifact from one set of attributes to another. You call `dependencies.registerTransform(MyTransformAction::class) { from.attribute(ARTIFACT_TYPE, "jar"); to.attribute(ARTIFACT_TYPE, "classes") }`. The `from` attribute container describes the artifacts the transform consumes (its inputs), and `to` describes what it produces. Gradle's variant-matching engine then knows that whenever a consumer requests the `to` attributes but only the `from` variant is available, it can insert this transform to bridge the gap. Registration is declarative — it does not run anything; it just adds the rule to the project's set of available transforms. The actual conversion happens lazily, only when a resolution actually requests the target attributes.

code

kotlin · 8 lines
kotlin
val artifactType = Attribute.of("artifactType", String::class.java)

dependencies {
    registerTransform(Unzip::class) {
        from.attribute(artifactType, "jar")
        to.attribute(artifactType, "classes")
    }
}

go deeper

for a junior

Know it's dependencies.registerTransform(Type) { from.attribute(...); to.attribute(...) } and that from = inputs, to = outputs.

for a middle

Explain that from/to drive variant matching and that registration is declarative and lazy, with outputs cached.

for a senior

Discuss how the matching engine can chain transforms automatically and how artifactType is implicit from file extension.

for a principal

Frame transforms as a way to keep cross-cutting artifact processing out of build logic and reproducible/cacheable across a large build.

## What registration is An **artifact transform** is a rule that converts a resolved artifact (a file) from one *shape* to another. The shape is described by Gradle **attributes** — typed key/value pairs attached to variants and artifacts (e.g. `artifactType`, or custom ones like `minified`). Registration is the act of *declaring that such a rule exists*. You do it on the `dependencies` block: ```kotlin dependencies { registerTransform(Unzip::class) { from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "jar") to.attribute(ARTIFACT_TYPE_ATTRIBUTE, "classes") } } ``` `registerTransform(Type) { ... }` takes the **TransformAction** class and a configuration block exposing two attribute containers: - **`from`** — the attributes of the artifacts this transform *consumes*. It is the precondition: an artifact must match these to be eligible. - **`to`** — the attributes of the artifacts this transform *produces*. It is the postcondition: after running, the output is tagged with these. ## How matching uses from/to Gradle has a single **variant-matching** engine. When you resolve a configuration and request a target attribute set, Gradle looks for a variant that already matches. If none does, it searches the registered transforms for a chain whose `from` matches an available variant and whose `to` matches what you asked for. It can even **chain** multiple transforms (A→B then B→C) automatically. The `ARTIFACT_TYPE_ATTRIBUTE` (`Attribute<String>` named `artifactType`) is the most common one because every artifact has an implicit `artifactType` derived from its file extension (`jar`, `aar`, `zip`, ...). ## Registration is declarative and lazy `registerTransform` does **not** execute the transform. It only adds the rule. The TransformAction runs **on demand**, and only when some resolution actually requests the `to` attributes — typically through an `artifactView`. Outputs are cached, so a given input/parameters pair is transformed once. ## Parameters If your transform needs configuration, the action implements `TransformAction<Parameters>` and you set `parameters { ... }` inside the registration block. Registration is where parameter *values* are bound; the action body reads them.

  • Does calling registerTransform run the transform immediately?
    No. Registration only adds the rule. The TransformAction executes lazily, only when a resolution actually requests the `to` attributes, and the result is cached.
  • What attribute is most commonly used in from/to?
    `artifactType` (a built-in `Attribute<String>`), because every artifact has an implicit artifactType from its file extension — jar, aar, zip, etc.

Registering a transform is like telling a kitchen 'I can turn raw beans (from) into ground coffee (to)' — the rule exists, but nobody grinds anything until an order for ground coffee comes in.

saying these in an interview costs you the question

  • Saying registerTransform executes the transform immediately.
  • Confusing `from`/`to` with input/output files — they are attribute sets, not paths.
  • Claiming you must request transforms manually; Gradle inserts them automatically during matching.

context