Convention Plugins

Usually, subprojects in a multi-project build share some common traits. For example, several subprojects may contain code in a particular programming language while another subproject may be dedicated for documentation. Code quality rules apply to all of the code subprojects but not the documentation subproject. At the same time, the subprojects that share one common trait may serve different purposes - they may produce different artifact types that further differentiate them, for example:

  • public libraries - libraries that are published to some repository

  • internal libraries - libraries on which other subprojects depend on internally within the project

  • command line applications - applications with specific packaging requirements

  • web services - applications with specific packaging requirements that are different from above

  • etc

Some other code subprojects may be dedicated for testing purposes and so on.

The traits above identify a subproject’s type. Or in other words, a subproject’s type tells us what traits the project has.

Gradle’s recommended way of organizing build logic is to use its plugin system. A plugin should define the type of a subproject. In fact, Gradle core plugins are modeled in the same way - for example, the Java Plugin configures a generic java project, while Java Library Plugin internally applies the Java Plugin and configures aspects specific to a Java library in addition. Similarly, the Application Plugin applies and configures the Java Plugin and the Distribution Plugin.

You can compose custom build logic by applying and configuring both core and external plugins and create custom plugins that define new project types and configure conventions specific to your project or organization. For each of the example traits from the beginning of this section, we can write a plugin that encapsulates the logic common to the subproject of a given type.

We recommend putting source code and tests for the convention plugins in the special buildSrc directory in the root directory of the project. For more information about buildSrc, consult Using buildSrc to organize build logic.

Another, more complex and real-world example of a multi-project build that composes build logic using convention plugins is the build of the Gradle Build Tool itself.

Cross project configuration

Another, discouraged, way to share build logic between subproject is cross project configuration via the subprojects {} and allprojects {} DSL constructs. With cross configuration, build logic can be injected into a subproject and this is not obvious when looking at the subproject’s build script, making it harder to understand the logic of a particular subproject. In the long run, cross configuration usually grows complex with more and more conditional logic and a higher maintenance burden. Cross configuration can also introduce configuration-time coupling between projects, which can prevent optimizations like configuration-on-demand from working properly.

There are two most common uses of cross-configuration that can be better modelled using convention plugins:

  • Applying plugins or other configuration to subprojects of certain type. Often the cross-configuration section will do if subproject is of type X, then configure Y. This is equivalent to applying X-conventions plugin directly to a subproject.

  • Extracting information from subprojects of a certain type. This use case can be modelled using outgoing configuration variants.