# How to Configure Property Load Order with LoadType.FIRST vs LoadType.MERGE in OWNER

> Learn how to configure property load order in OWNER using LoadType FIRST vs MERGE. Control property source precedence and handle duplicate keys effectively.

- Repository: [Matteo Baccan/owner](https://github.com/matteobaccan/owner)
- Tags: deep-dive
- Published: 2026-03-07

---

**OWNER determines property source precedence through the `@LoadPolicy` annotation, which accepts either `LoadType.FIRST` to stop at the first readable source or `LoadType.MERGE` to combine all sources with the first-declared URI taking precedence for duplicate keys.**

The OWNER configuration library (matteobaccan/owner) manages how multiple property files are consumed by your application. By default, the framework employs a **first-match-wins** strategy, but you can override this to layer configurations using the `MERGE` policy defined in `org.aeonbits.owner.Config.LoadType`.

## Understanding the LoadType Enumeration

The load behavior is controlled by the `LoadType` enum defined in [[`owner/src/main/java/org/aeonbits/owner/Config.java`](https://github.com/matteobaccan/owner/blob/main/owner/src/main/java/org/aeonbits/owner/Config.java)](https://github.com/matteobaccan/owner/blob/master/owner/src/main/java/org/aeonbits/owner/Config.java) (lines 123-150). This enum provides two constants:

- **`LoadType.FIRST`** – Loads the first successfully readable source from the `@Sources` list and stops immediately.
- **`LoadType.MERGE`** – Loads all reachable sources in reverse order, merging them into a single `Properties` object where earlier declarations override later ones.

During object construction, `PropertiesManager` extracts this policy in its constructor ([[`owner/src/main/java/org/aeonbits/owner/PropertiesManager.java`](https://github.com/matteobaccan/owner/blob/main/owner/src/main/java/org/aeonbits/owner/PropertiesManager.java)](https://github.com/matteobaccan/owner/blob/master/owner/src/main/java/org/aeonbits/owner/PropertiesManager.java), lines 97-107). If no `@LoadPolicy` annotation is present, the system defaults to `FIRST` via the assignment `loadType = (loadPolicy != null) ? loadPolicy.value() : FIRST;`.

## Using LoadType.FIRST for Fallback Hierarchies

The `FIRST` strategy processes the `@Sources` list sequentially from top to bottom. It attempts to load each URI until one succeeds, then returns immediately without processing remaining sources. This creates a clean fallback chain where missing or unreadable files are silently skipped via the `ignore()` mechanism.

Use this approach when you need a clear priority order, such as checking for a user-specific override before falling back to bundled defaults.

```java
@Sources({
    "file:${user.home}/app.conf",    // Try user-specific file first
    "classpath:default.properties"   // Fallback to classpath default
})
public interface AppConfig extends Config {
    String host();
    int port();
}

```

In this example, OWNER attempts to load the file from the user's home directory. Only if that file is missing or unreadable does it proceed to load `default.properties` from the classpath. The effective configuration contains properties from exactly one source.

## Using LoadType.MERGE for Configuration Layering

The `MERGE` strategy inverts the `@Sources` list using `reverse(uris)` and loads every reachable file into the same `Properties` object. Because the list is processed in reverse, the **first entry in your annotation has the highest precedence**. When the same key exists in multiple files, the value from the earliest source in the list prevails, as subsequent loads cannot overwrite existing entries.

Use this when you need to combine base configurations with environment-specific overlays.

```java
@Sources({
    "classpath:base.properties",           // Highest priority (declared first)
    "classpath:environment.properties",    // Overrides base only for new keys
    "file:/etc/app/override.properties"    // Lowest priority
})
@LoadPolicy(LoadType.MERGE)
public interface LayeredConfig extends Config {
    String databaseUrl();
    String logLevel();
}

```

Here, all three files are loaded. If `databaseUrl` appears in both `base.properties` and `environment.properties`, the value from `base.properties` wins because it appears first in the annotation list. This behavior is verified in the unit test [[`MergeLoadStrategyTest.java`](https://github.com/matteobaccan/owner/blob/main/MergeLoadStrategyTest.java)](https://github.com/matteobaccan/owner/blob/master/owner/src/test/java/org/aeonbits/owner/loadstrategies/MergeLoadStrategyTest.java).

## Implementation Behavior for Missing Resources

Both strategies handle unreachable URIs identically: they invoke the `ignore()` method and continue processing. This means your application will not crash if a fallback file is missing, regardless of whether you use `FIRST` or `MERGE`. The difference lies solely in how many sources are ultimately incorporated into the final configuration object.

## Summary

- **`LoadType.FIRST`** processes `@Sources` in declared order and stops at the first successful load, creating a single-source configuration ideal for fallback chains.
- **`LoadType.MERGE`** reverses the source list, loads all reachable files, and merges them so that the first-declared source takes precedence for overlapping keys.
- The default policy is `FIRST` when no `@LoadPolicy` annotation is specified, as implemented in [`PropertiesManager.java`](https://github.com/matteobaccan/owner/blob/main/PropertiesManager.java).
- Both policies silently skip missing or unreadable URIs, allowing optional configuration files in your hierarchy.

## Frequently Asked Questions

### What is the default load policy in OWNER?

If you do not annotate your configuration interface with `@LoadPolicy`, OWNER defaults to `LoadType.FIRST`. This is explicitly set in the `PropertiesManager` constructor at line 107, where `loadType` is assigned `FIRST` when no annotation is detected.

### How does LoadType.MERGE handle duplicate property keys?

When using `MERGE`, OWNER iterates through the `@Sources` list in reverse order. Because the `Properties` object retains the first value written for any key, the source that appears **first** in your annotation (processed last in the reversed iteration) wins for duplicate keys. Later loads cannot overwrite existing entries.

### Can I use different LoadType strategies for different configuration interfaces?

Yes. Each configuration interface is independent, and `ConfigFactory.create()` instantiates a separate `PropertiesManager` for each one. You can annotate `DatabaseConfig` with `@LoadPolicy(MERGE)` while leaving `SecurityConfig` to use the default `FIRST` behavior.

### Does OWNER throw an exception if a source file is missing?

No. Both `FIRST` and `MERGE` strategies silently ignore unreachable URIs through the `ignore()` mechanism in the loading logic. The framework only throws an exception if a successfully loaded file contains invalid data or if a required property key is missing from the final merged result.