# Platform

The Quarkus extension ecosystem consists of the Quarkus extensions developed and maintained by the community, including the Quarkus core development team. While the Quarkus ecosystem (sometimes also referred to as the "Quarkus universe") includes all the Quarkus extensions ever developed, there is also a concept of a Quarkus platform.

## Quarkus Platform

The fundamental promise of a Quarkus platform is any combination of the Quarkus extensions the platform consists of can be used in the same application without causing any conflict for each other. Each organization creating their Quarkus platform may establish their own criteria for the extensions to be accepted into the platform and the means to guarantee the compatibility between the accepted extensions.

### Quarkus Platform Artifacts

Each Quarkus platform is defined with a few artifacts.

### Quarkus Platform BOM

Each Quarkus Platform is expected to provide a Maven BOM artifact that

- imports a chosen version of `io.quarkus:quarkus-bom` (the platform BOM may be flattened at the end, but it has to be based on some version of `io.quarkus:quarkus-bom`)

- includes all the Quarkus extension artifacts (the runtime and the deployment ones) the platform consists of

- includes all the necessary third-party artifacts that align the transitive dependency versions of the platform extensions to guarantee compatibility between them

- includes the platform JSON descriptor artifact

- possibly includes the platform configuration properties artifacts

Quarkus applications that want to include extensions from a Quarkus platform will be importing the Quarkus platform BOM.

### Quarkus Platform Descriptor

Quarkus platform descriptor is a JSON artifact that provides information about the platform and its extensions to the Quarkus tools. E.g. https://code.quarkus.io/ and the Quarkus command line tools consult this descriptor to list, add and remove extensions to/from the project on user’s request. This artifact is also used as a Quarkus platform identifier. When Quarkus tools need to identify the Quarkus platform(s) used in the project, they will analyze the dependency version constraints of the project (the effective list of the managed dependencies from the `dependencyManagement` section in Maven terms) looking for the platform descriptor artifact(s) among them. Given that the platform descriptors are included into the Quarkus platform BOMs, every Quarkus application will inherit the platform descriptor artifact from the imported platform BOM(s) as a dependency version constraint (managed dependency in Maven terms).

To be able to easily identify Quarkus platform descriptors among the project’s dependency constraints, the platform descriptor Maven artifact coordinates should follow the following naming convention:

- the `groupId` of the descriptor artifact should match the `groupId` of the corresponding Quarkus Platform BOM;

- the `artifactId` of the descriptor artifact should be the `artifactId` of the corresponding Quarkus Platform BOM with the `-quarkus-platform-descriptor` suffix;

- the `classifier` of the descriptor artifact should match the `version` of the corresponding Quarkus Platform BOM;

- the `type` of the descriptor artifact should be `json`;

- the `version` of the descriptor artifact should match the `version` of the corresponding Quarkus Platform BOM.

As a string it will look like `<platform-bom-groupId>:<platform-bom-artifactId>-quarkus-platform-descriptor:<platform-version>:json:<platform-version>`

E.g. the coordinates of the descriptor for the Quarkus BOM `io.quarkus.platform:quarkus-bom::pom:1.2.3` will be `io.quarkus.platform:quarkus-bom-quarkus-platform-descriptor:1.2.3:json:1.2.3`. And for a custom Quarkus platform defined with BOM `org.acme:acme-bom::pom:555` it will be `org.acme:acme-bom-quarkus-platform-descriptor:555:json:555`.

The classifier matching the version of the platform may look confusing at first. But this is what turns the descriptor into a true "fingerprint" of the platform. In both Maven and Gradle, the effective set of the dependency version constraints (or the managed dependencies) is obtained by merging all the imported BOMs and version constraints specified individually in the current project and also its parent(s). The artifact `classifier` is a part of the dependency ID, which could be expressed as `groupId:artifactId:classifier:type`. Which means that if a project imports a couple of BOMs, e.g. `org.apple:apple-bom::pom:1.0` and `org.orange:orange-bom::pom:1.0`, and each of these two BOMs imports a different version `io.quarkus.platform:quarkus-bom::pom`, the Quarkus tools will be able to detect this fact and make the user aware of it, since it might not be a safe combination. If the descriptor artifact didn’t include the classifier containing the version of the platform then the tools wouldn’t be able to detect a potentially incompatible mix of different versions of the same platform in the same project.

The platform descriptor will normally be generated using a Maven plugin, e.g.

    <plugin>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-platform-descriptor-json-plugin</artifactId>
      <version>${quarkus.version}</version> (1)
      <executions>
        <execution>
          <phase>process-resources</phase>
          <goals>
            <goal>generate-extensions-json</goal> (2)
          </goals>
        </execution>
      </executions>
      <configuration>
        <bomGroupId>${quarkus.platform.group-id}</bomGroupId> (3)
        <bomArtifactId>${quarkus.platform.artifact-id}</bomArtifactId> (4)
        <bomVersion>${quarkus.platform.version}</bomVersion> (5)
        <overridesFile>${overridesfile}</overridesFile> (6)
        <resolveDependencyManagement>true</resolveDependencyManagement> (7)
      </configuration>
    </plugin>

1 | the version of the `quarkus-platform-descriptor-json-plugin`
2 | `generate-extensions-json` is the goal generating the platform descriptor
3 | the `groupId` of the platform BOM
4 | the `artifactId` of the platform BOM
5 | the `version` of the platform BOM
6 | this parameter is optional, it allows to override some metadata from the Quarkus extension descriptors found in every runtime extension artifact from which the platform descriptor is generated
7 | this parameter is also optional and defaults to false. It has to be set to true in case the platform BOM is not generated and is not flattened. Which for example is the case for `io.quarkus:quarkus-bom`.

### Quarkus Platform Properties

A Quarkus platform may provide its own default values for some configuration options.

Quarkus is using SmallRye Config for wiring application configuration. A Quarkus platform may be used as another source of configuration in the hierarchy of the configuration sources dominated by the application’s `application.properties`.

To provide platform-specific defaults, the platform needs to include a dependency version constraint in its BOM for a properties artifact whose coordinates follow the following naming convention:

- the `groupId` of the properties artifact should match the `groupId` of the corresponding Quarkus Platform BOM;

- the `artifactId` of the properties artifact should be the `artifactId` of the corresponding Quarkus Platform BOM with the `-quarkus-platform-properties` suffix;

- the `classifier` of the descriptor artifact should be left empty/null;

- the `type` of the descriptor artifact should be `properties`;

- the `version` of the descriptor artifact should match the `version` of the corresponding Quarkus Platform BOM.

The properties artifact itself is expected to be a traditional `properties` file that will be loaded into an instance of `java.util.Properties` class.

| At this point, platform properties are only allowed to provide the default values for a restricted set of configuration options. The property names in the platform properties file must be prefixed with the `platform.` suffix.

Extension developers that want to make their configuration options platform-specific should set their default values to properties that start with the `platform.` suffix. Here is an example:

    package io.quarkus.deployment.pkg;

    @ConfigRoot(phase = ConfigPhase.BUILD_TIME)
    @ConfigMapping(prefix = "quarkus")
    public interface NativeConfig {

        /**
         * The docker image to use to do the image build
         */
        @WithDefault("${platform.quarkus.native.builder-image}")
        String builderImage();
    }

In this case the default value for `quarkus.native.builder-image` will be provided by the platform. The user will still be able to set the desired value for `quarkus.native.builder-image` in its `application.properties`, of course. But in case it’s not customized by the user, the default value will be coming from the platform properties. A platform properties file for the example above would contain:

    platform.quarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-17

There is also a Maven plugin goal that validates the platform properties content and its artifact coordinates and also checks whether the platform properties artifact is present in the platform’s BOM. Here is a sample plugin configuration:

    <plugin>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-platform-descriptor-json-plugin</artifactId>
      <version>${quarkus.version}</version>
      <executions>
        <execution>
          <phase>process-resources</phase>
          <goals>
            <goal>platform-properties</goal>
          </goals>
        </execution>
      </executions>
    </plugin>

#### Merging Quarkus Platform Properties

In case an application is importing more than one Quarkus platform and those platforms include their own platform properties artifacts, the content of those platform properties artifacts will be merged to form a single set of properties that will be used for the application build. The order in which the properties artifacts are merged will correspond to the order in which they appear in the list of dependency version constraints of the application (in the Maven terms that will correspond to the effective list of application’s managed dependencies, i.e. the flattened `managedDependencies` POM section).

| The content of the properties artifacts found earlier will dominate over those found later among the application’s dependency constraints!

That means if a platform needs to override a certain property value defined in the platform it is based on, it will need to include its platform properties artifact into the `managedDependencies` section of its BOM before importing the base platform.

For example, let’s assume `org.acme:acme-quarkus-bom` platform extends the `io.quarkus:quarkus-bom` platform by importing its BOM. In case, the `org.acme:acme-quarkus-bom` platform were to override certain properties defined in the `io.quarkus:quarkus-bom-quarkus-platform-properties` included in the `io.quarkus:quarkus-bom`, the `org.acme:acme-quarkus-bom` would have to be composed as

      <!-- skipped content -->

      <artifactId>acme-quarkus-bom</artifactId>
      <name>Acme - Quarkus - BOM</name>
      <packaging>pom</packaging>

      <dependencyManagement>
        <dependencies>
          <!-- Acme Quarkus platform properties -->
          <dependency>
            <groupId>org.acme</groupId>
            <artifactId>acme-quarkus-bom-quarkus-platform-properties</artifactId>
            <type>properties</type>
            <version>${project.version}</version>
          </dependency>

          <!-- The base Quarkus BOM -->
          <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-bom</artifactId>
            <version>${quarkus.version}</version>
            <type>pom</type>
            <scope>import</scope>
          </dependency>

      <!-- skipped content -->

That way, the `org.acme:acme-quarkus-bom` platform properties will appear before those provided by the `io.quarkus:quarkus-bom` properties and so will be dominating at build time.