Laminas Framework Series: Getting Started with Mezzio

Doğan Uçar
7 min readNov 20, 2023


In the third post of the Laminas Framework Series we will address the getting started with Mezzio. The Laminas Framework, though comparatively recent as an independent entity, originates as a complete fork and successor of the Zend Framework, embedding it firmly in the realm of PHP-based enterprise software development. Mezzio, previously recognized as Expressive, is fundamentally built around the concept of middleware.

The first blog post addressed “Background and Basics” and the second post was about middlewares in Mezzio. While each post is independent and does not require the knowledge from it successor(s), it is highly recommended to read them first to have a good overview to Laminas.

This following article will guide you through configuring Mezzio, enabling you to begin coding in just a few minutes. It includes an overview of the Mezzio Skeleton Installer, a tool that caters to almost every aspect of Mezzio development. For those seeking greater control over their project’s structure, there will also be an option to sign up for my newsletter, where I offer a comprehensive guide on tailor-made project setups using Mezzio.

Did you know that Keestash is built with Mezzio? Check out the repository or sign up to use Keestash for free!

Prerequisites and Environment

At the time this article was written, the latest version of Mezzio was 3.14.0 which requires PHP 8.x. So to be able to work with Mezzio, you just need to make sure you have a higher than 8 installed. Apart of PHP, Composer will be the central tool to do almost everything around dependencies: install, remove, update and much more.

Mezzio enables the creation of web applications using PSR-15 middleware, which interacts with PSR-7 HTTP Message Interfaces to handle incoming requests and outgoing responses. This combination of PSR-15 and PSR-7 standards ensures compatibility across various contexts. Middleware, the core of Mezzio, acts as an intermediary between a request and a response. I addressed middlewares in the second post of this series.

Mezzio is built on laminas-stratigility for its foundational layer, offering features like dynamic routing, which surpasses Stratigility’s basic path matching. It supports various routers and allows for HTTP method-specific route matching, handling invalid requests with appropriate responses.

Further, Mezzio supports Dependency Injection natively by implementing the PSR-11 ContainerInterface for lazy-loading middleware. While Mezzio does not implement templating, however, it provides an abstraction for well known packages, allowing developers to work with layout and namespaced templates within their middleware.

Error handling in Mezzio is adaptable to different environments, such as development or production. It uses Stratigility’s ErrorHandler along with customizable error response generators for efficient and appropriate error management.

Creating a new Mezzio Project Basic Configuration

The central tool for working with Mezzio is Composer (as for all modern PHP applications). The built-in CLI is very powerful and gives a lot of tools to make development easier. The Mezzio Skeleton Installer uses the create-project command to checkout the skeleton and guide you through the installation via an interface UI:

As the screenshot shows, the installer will ask some questions in order to complete the setup. Briefly, the questions are:

  • Type of Installation: upon choice, Mezzio will install or remove additional resources. I typically select the default (2).
  • Dependeny Injection Container: Mezzio lets you the choice of which DI container you want to use. I usually go for laminas-servicemanager in order to avoid possibly incompatibilities or performance issues.
  • HTTP Router: as with the DI implementation, Mezzio also allows the usage of different routers. I suggest using laminas-router and you should be aware that choosing the right router can be essential. Pattern matching for modern REST routes uses regex intensively which can be a performance issue if badly implemented.
  • Template Engine: Same here — Mezzio gives you the choice for templating. As I usually use Mezzio as API’s only, I do not need a template engine (1).
  • Visual Error Handler: technically, Mezzio gives you the choice here too. But there is just Whoops or nothing, so thus in reality, you have only one handler or nothing. I recommend using no visual error handler and have a good logging strategy. You will need this for production anyway and having the luxury of visual errors will likely make you lazy and prevent from implement it (2).
  • Config Injection: Mezzio can inject the ConfigProvider’s for the following modules: Validator, HttpHandlerRunner, Router, Tooling, Helper and Twig into the global config.php file. Select those you want to use in your application.

Understanding the Project Setup

So far, we set up a mezzio application using the skeleton installer. The project should now look like:

Unfortunately, the official Mezzio documentation does not provide much about the structure. Much of the following information is based on my experience and going through the code. If you find any errors please let me know.

Most of the files and folders are framework related and are not of interest during development. We will therefore focus on the following:


The src/ folder is the central place for all custom source code of the application, bundling PHP classes such as controllers, middleware, services, and models. This organization not only aids in maintaining a clear namespace structure for autoloading but also ensures a separation of concerns by distinguishing application-specific code from third-party libraries, templates, and configurations. As the application expands, the src/ folder’s scalability becomes evident, with the potential for subdirectories that cater to different modules or components.

Complementing this, ConfigProviders play a pivotal role in aggregating and managing the application’s configuration. These PHP classes return arrays of configurations for various application aspects, including middleware, routes, and dependency injection containers. Their modular nature allows each component or module to have its own ConfigProvider, organizing the management and understanding of configurations related to specific application parts. This modular approach not only simplifies the integration of new features and third-party modules but also centralizes configuration management, reducing duplication and potential errors. Source code organized in this way is named Module in the world of Mezzio.


In a Mezzio application, the test folder is dedicated to housing the test suites and test cases for the application. The primary purpose of this directory is to organize and store all the unit tests, integration tests, and potentially other types of tests like functional or acceptance tests, that are designed to verify the correctness and reliability of the application’s code.

Moreover, Mezzio’s emphasis on modular and middleware-driven architecture often requires tests to be written in a way that reflects this structure. This could involve mock objects and stubs to isolate components, ensuring that each part of the application can be tested independently without requiring the entire application to be up and running.

Testing in Mezzio is further supported by its use of a dependency injection container. This allows for the isolated testing of individual components by mocking dependencies and services, a crucial aspect of unit testing. Additionally, the framework’s routing and dispatch mechanisms can be thoroughly tested to confirm that routes are correctly configured and that the appropriate handlers are dispatched for different URLs.


The config folder is a critical component for managing the application’s configurations and environment-specific settings. This folder houses various configuration files that leads the application’s behavior in different environments and scenarios. The config folder is also the place where the ConfigProviders are bundled.

The global.php files within this directory are designed for universal settings applicable in all environments, such as middleware configurations and database settings. These settings form the baseline for the application’s operation.

Contrastingly, the local.php files cater to environment-specific configurations. These files typically hold settings that vary from one environment to another, like sensitive credentials and debug flags. Since these files contain environment-sensitive data, they are not usually included in version control and are tailored for each deployment.

The dist files in the config folder act as templates or examples for configuration files. They are particularly useful during initial setup or when deploying the application in a new environment. By copying and renaming these dist files (often to local.php), developers can create environment-specific configurations efficiently.

Additionally, the autoload subfolder within the config directory plays a vital role in organizing the application’s configuration files. Mezzio’s modular approach to application development is reflected in this subfolder, where configurations for specific modules or components are stored. This structure not only keeps the configurations organized but also simplifies the management of larger applications with numerous components. The framework automatically loads these configurations, allowing them to override or complement the global settings.

Overall, the config folder’s structured approach in Mezzio ensures a flexible, scalable, and organized method of configuring the application, enabling it to adapt seamlessly to various environments and operational needs.

Use the Subscription form in the original post on my website to get the guide:


Mezzio is powerful, comes with a lot of tools and documentation and is based on a proven and enterprise framework (Laminas a.k.a. Zend). Choosing Mezzio for enterprise applications will definitely end up in scaling and modern applications. Backed by a core team of developers and a community, you can rely on further framework development and help.

This guide will be part of my upcoming Mezzio book. Subscribe to my newsletter in the form above and be one of the first getting notified the release announcement.

(1) Sometimes, against all odds, I do need a template engine — e.g. for e-mails. In this case, I use Twig, as this is where I have the most experience.

(2) this can also be very useful for creating dashboards or setting up alerting tools with tools like Sentry or DataDog.



Doğan Uçar

Software Engineer, PHP/Laminas (Zend), Backend, Cloud, Freelancer & CEO, Open Source Contributor