Migration to Laminas FAQ


Module and Config Post Processor injection

If you are migrating an MVC, Apigility, or Expressive application to Laminas, the migration tooling attempts to inject some code in your application. This can fail if you have non-standard configuration.

Migrating MVC and Apigility applications

When migrating MVC and Apigility applications to Laminas MVC and Laminas API Tools, the migration tooling attempts to add Laminas\ZendFrameworkBridge as a module to the top of the config/modules.config.php file. If injection fails, add the module in a way appropriate to your application.


When migrating Expressive applications to Mezzio, the migration tooling attempts to add Laminas\ZendFrameworkBridge\ConfigPostProcessor as a post processor class to the ConfigAggregator constructor. The ConfigAggregator constructor has the following signature:

public function __construct(
    array $providers = [],
    ?string $cachedConfigFile = null,
    array $postProcessors = []

Typically, the structure of the config/config.php file in Expressive and Mezzio applications looks like the following:

$cacheConfig = [
    'config_cache_path' => 'data/cache/app_config.php',

$aggregator = new ConfigAggregator([
    // config providers from 3rd party code
    // ...

    // App-specific modules
    // ...

    // Include cache configuration
    new ArrayProvider($cacheConfig),

    // Load application config in a pre-defined order in such a way that local settings
    // overwrite global settings. (Loaded as first to last):
    //   - `global.php`
    //   - `*.global.php`
    //   - `local.php`
    //   - `*.local.php`
    new PhpFileProvider('config/autoload/{{,*.}global,{,*.}local}.php'),

    // Load development config if it exists
    new PhpFileProvider('config/development.config.php'),
], $cacheConfig['config_cache_path']);

return $aggregator->getMergedConfig();

As such, the migration tooling rewrites the second to last line to read:

], $cacheConfig['config_cache_path'], [\Laminas\ZendFrameworkBridge\ConfigPostProcessor::class]);

In most cases, failure to inject means that the individual arguments have been pushed to their own line. In such cases, add the third argument as detailed above.

In other cases, applications may already be using post processors. If so, add \Laminas\ZendFrameworkBridge\ConfigPostProcessor::class to the list of post processors.

Clear your caches

If your application is not running in development mode, you will need to clear any configuration caches you have before testing. If you are using zf-development-mode (which becomes laminas-development-mode!), try enabling development mode:

$ composer development-enable

Expressive/Mezzio users can use the clear-config-cache command:

$ composer clear-config-cache

Zend Framework v1 Considerations

Zend Framework version 1 is past end of life, so it does not receive any rewrites during migration. However, custom code in the project being migrated does receive rewrites. This has the potential to cause errors.


The Zend_Mail component uses a "ZendMail_" prefix for filenames generated by the Zend_Mail_Transport_File transport. After migration, this transport adapter will continue to generate filenames using the "ZendMail_" prefix. Any custom code that also references the "ZendMail_" prefix will be rewritten to instead use a prefix of "LaminasMail_".

Since the v1 Zend_Mail component and later versions both use the same "ZendMail_" prefix, the migration cannot discriminate when rewriting custom project code. Consequently, you will need to reconcile any errors in your code arising from this prefix rewrite.