One of the key pillars of Magento 2 is its Dependency Injection (DI) system.
Thanks to it, the platform remains flexible and scalable. However, this system relies on a set of sometimes mysterious files — the famous di.xml files.
These files contain the configuration for various mechanisms such as plugins or observers. However, some very important elements within these same files often cause confusion: <type> and <virtualType>.
Yet, they are essential for customizing the behavior of Magento services without modifying the core code.
1. Dependency Injection in a Few Words
Dependency Injection means providing a class with the objects it depends on, instead of creating them directly inside the class.
In other words, Magento takes care of instantiating dependencies and injecting them automatically into constructors.
Classic example without DI
class MyClass {
private $logger;
public function __construct() {
$this->logger = new Logger();
}
}
In this example, the MyClass class creates its own Logger instance.
As a result, it’s hard to replace that dependency with another implementation without changing the code.
Example with DI
class MyClass {
private $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
}
Thanks to di.xml, Magento can decide which implementation of LoggerInterface to use — without MyClass needing to know it.
And that’s exactly where the <type> and <virtualType> tags come into play.
2. The Role of the <type> Tag
The <type> tag allows you to configure a real existing class in the PHP code.
It’s used to modify injected dependencies or redefine certain arguments.
Example
<type name="Magento\Checkout\Model\Session">
<arguments>
<argument name="logger" xsi:type="object">My\Module\Logger\CheckoutLogger</argument>
</arguments>
</type>
In this example:
namecorresponds to a real class (Magento\Checkout\Model\Session).- We simply redefine its
loggerargument to useCheckoutLogger.
Each time Magento creates a Magento\Checkout\Model\Session, it will now use My\Module\Logger\CheckoutLogger instead of the default logger.
3. The Role of the <virtualType> Tag
The <virtualType> tag looks similar to <type>, but with one key difference: it does not correspond to a physical class.
A virtual type is a configuration derived from another class, allowing you to create a new “variant” without writing a new PHP file.
Example
<virtualType name="My\Module\Model\CustomSession" type="Magento\Checkout\Model\Session">
<arguments>
<argument name="logger" xsi:type="object">My\Module\Logger\CustomLogger</argument>
</arguments>
</virtualType>
Here:
type="Magento\Checkout\Model\Session"means our virtual type is based on that class.name="My\Module\Model\CustomSession"is the symbolic name of the virtual type (it doesn’t exist as a real class).
4. Practical Example: Using a Virtual Type Inside a Type
Let’s take a concrete example.
We have a PriceCalculator class that calculates prices and logs some information.
We want to inject a special logger with a specific log level (info, warning, debug), without creating a new PHP class.
Step 1: Create the virtual type
<virtualType name="My\Module\Model\DebugLogger" type="My\Module\Model\Logger">
<arguments>
<argument name="level" xsi:type="string">debug</argument>
</arguments>
</virtualType>
DebugLoggeris based onLogger, but its log level is configured asdebug.- No additional PHP file is required.
Step 2: Inject the virtual type into PriceCalculator using a <type>
<type name="My\Module\Model\PriceCalculator">
<arguments>
<argument name="logger" xsi:type="object">My\Module\Model\DebugLogger</argument>
</arguments>
</type>
This way:
PriceCalculatorreceives the configuredDebugLogger.- All other classes that use
Loggerremain unaffected.
5. Conclusion
<type>: configures an existing, real PHP class.<virtualType>: creates a configured variant of an existing class — without creating a new PHP file.- Combined, these two tags allow you to reuse and customize Magento services cleanly and modularly.
Magento 2 owes much of its flexibility to its Dependency Injection system.
By using <type> and <virtualType> in your di.xml, you can create class variants and adjust their behavior — all while keeping your code clean, maintainable, and upgrade-safe.

