.agents/skills/working-with-config/SKILL.md
Quarkus configuration must use @ConfigMapping interfaces. The legacy
@ConfigRoot-annotated classes with @ConfigItem have been fully removed
(see adr/0008-phasing-out-config-classes.adoc).
@ConfigMapping(prefix = "quarkus.my-extension")
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
public interface MyExtensionRuntimeConfig {
/** Description of the property. */
@WithDefault("default-value")
String myProperty();
/** Optional property (absent means not set by the user). */
Optional<String> optionalProperty();
}
Never use Optional and provide a default via .orElse(...) in application
code. The default must be declared in the config mapping itself via
@WithDefault:
// BAD — do not do this
String name = config.optName().orElse("theDefaultName");
// GOOD — declare the default in the config mapping
@WithDefault("theDefaultName")
String name();
@ConfigMapping can also be used without @ConfigRoot for non-root
mappings. These are not auto-discovered — you must register them explicitly
(e.g., via @Inject in a CDI bean or programmatically with SmallRye Config).
Use this when mapping a sub-tree of configuration that does not represent an
extension's top-level config root.
@ConfigMapping(prefix = "some.custom.prefix")
public interface MyCustomConfig {
/** A non-root config property. */
String someValue();
}
// DO NOT use this pattern
@ConfigRoot(name = "my-extension", phase = ConfigPhase.RUN_TIME)
public class MyExtensionConfig {
@ConfigItem(defaultValue = "default-value")
String myProperty;
}
@ConfigRoot defaults to BUILD_TIME when no phase is specified. Always set
the phase explicitly — omitting it for a config injected at runtime will cause
UnsatisfiedResolutionException because BUILD_TIME configs are not registered
as CDI beans.
BUILD_TIME — Baked into the binary at build time, immutable at runtime.
Use for settings that affect code generation. Only available in @BuildStep
methods — not injectable via @Inject in runtime CDI beans.BUILD_AND_RUN_TIME_FIXED — Read at build time, also available at
runtime. Cannot change without rebuilding. Available in both @BuildStep
methods and runtime CDI beans.RUN_TIME — Read at application startup. Can change between runs.
Available in runtime CDI beans via @Inject. Not available in
@BuildStep methods.<Feature>Config.java, or split as
<Feature>BuildTimeConfig.java / <Feature>RuntimeConfig.javaquarkus.<extension-name>quarkus-extension-processor)The quarkus-extension-processor annotation processor is required for all
extension modules, not just those with @ConfigRoot. It generates metadata
files (including META-INF/quarkus-config-roots.list for config discovery)
that Quarkus needs to wire extensions correctly. Without it, most extension
functionality will silently fail.
Both runtime/ and deployment/ POMs must include:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
</plugin>
Most modules already have this. If you create a new module or notice missing
metadata, verify the annotation processor is present in its pom.xml.
phase explicitly on @ConfigRoot — the default is
BUILD_TIME, which is not injectable via CDI at runtimeRUN_TIME phase unless the config genuinely affects build-time behaviorRUN_TIME config during build steps — it is not available yetBUILD_TIME config changes require a rebuildquarkus.* properties, always register them in a
@ConfigMapping interface. Reading them programmatically via
ConfigProvider.getConfig().getOptionalValue(...) is fine, but the
corresponding key must still be defined in a @ConfigMapping — otherwise
SmallRye Config will emit "unknown property" warnings at startup.