Layered Configuration Aggregation with laminas-config-aggregator
Learn how to build a single merged configuration array from layered sources in a Laminas application using laminas-config-aggregator, with declarative precedence and no manual bootstrap merging.
05 Oct 2025, 11:21 UTC

Problem: scattered config with manual merging
Teams running Laminas MVC or Mezzio often end up with configuration split across global defaults, environment-specific files, and local overrides. Manual merging in bootstrap creates drift and makes precedence hard to audit.
Useful takeaway: let laminas-config-aggregator build one merged array during bootstrap with explicit layer order, so the ServiceManager and application code see a single configuration and precedence is declarative.
Desired outcome
A single merged configuration array available to the ServiceManager and application code, built from multiple layered sources with predictable precedence and no manual merging in bootstrap code. Later-added sources override earlier ones. The merged result participates in the normal Laminas config chain.
Prerequisites
- A Laminas MVC or Mezzio style application with laminas-config installed.
- laminas-config-aggregator available as a Composer dependency. Add it in the project root where composer.json resides.
- Configuration files organized in a known directory structure that can be referenced by the aggregator, for example: config/global, config/development, config/local.
- Assumption: Laminas components follow current Laminas Config and ServiceManager contracts. Major version changes may alter provider interfaces or config key expectations.
Focused procedure
Install the component
Run the following command in the project root with write permission to vendor and composer.lock.
composer require laminas/laminas-config-aggregator
Risk: adding a new dependency changes autoload and may affect deployment size. Review composer.lock in CI.
Create a config provider that aggregates layers
Create a provider class that instantiates an aggregator, adds sources in priority order, and returns the merged config. Later sources override earlier ones.
class AppConfigProvider { public function __invoke() { $aggregator = new ConfigAggregator([ new PhpFileProvider(__DIR__ . '/../config/global'), new PhpFileProvider(__DIR__ . '/../config/' . getenv('APP_ENV') ?: 'development'), new PhpFileProvider(__DIR__ . '/../config/local') ]); return [ 'config' => $aggregator->getMergedConfig() ]; } }
Register the provider in config/config.php so it runs during bootstrap. The order of providers in the aggregator defines precedence: global defaults first, environment second, local override last.
Organize sources
Keep each layer as a PHP file returning an array. Example structure:
- config/global/app.global.php returns base defaults
- config/development/app.development.php returns dev overrides
- config/local/app.local.php returns machine-specific overrides
Do not rely on implicit deep merge semantics. Verify merge behavior for nested arrays before relying on overrides, as deep versus shallow merge can vary by Laminas Config version and aggregator used.
Expected checks
- Verify merged config contains keys from all layers. Inspect the final merged config in a debug route or CLI script by dumping the config array returned by the application and confirming presence and values of keys from each layer.
- Confirm environment-specific values correctly override defaults. Temporarily add a unique marker value in each config source and confirm the marker that appears in the merged result matches the expected precedence.
- Confirm the ServiceManager receives the merged config under the expected key.
- Confirm changes to a source file are reflected after a cache clear.
Recovery options
- If merge order is incorrect or values are unexpected, revert the aggregator registration to a static config file while auditing precedence rules and source paths.
- Remove or disable an offending config source by commenting its provider in the aggregator list.
- Fall back to a known-good config snapshot and compare the merged output against the snapshot.
Disable the aggregator and load a static config to compare behavior, then re-enable it to ensure no regression in service configuration or routing.
Limitations
- Config aggregation order is significant; later added sources override earlier ones, which can cause unexpected values if environment layers are registered in the wrong sequence.
- Merge semantics for nested arrays should be verified for the specific Laminas Config version in use, as deep merge versus shallow merge behavior may differ.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.