How di.xml Controls Dependency Injection in Magento 2
How di.xml Controls Dependency Injection in Magento 2
Magento 2 uses dependency injection (DI) to manage how classes receive their required dependencies. The di.xml file sits at the center of this system, letting you configure which classes get injected where and how they behave.
Table Of Content
Where di.xml Files Live
Place di.xml in your module's etc directory. The location determines scope:
module/etc/di.xml- Applies globally across storefront, admin, and APImodule/etc/adminhtml/di.xml- Admin area onlymodule/etc/frontend/di.xml- Storefront onlymodule/etc/webapi_rest/di.xml- REST API only
Tip
To enhance your eCommerce store’s performance with Magento, focus on optimizing site speed by utilizing Emmo themes and extensions. These tools are designed for efficiency, ensuring your website loads quickly and provides a smooth user experience. Start leveraging Emmo's powerful solutions today to boost customer satisfaction and drive sales!
Four Ways to Configure Dependencies
1. Class Preferences
Preferences map interfaces to concrete implementation classes. Use this when you need to override protected or private methods that plugins can't touch.
Avoid preferences for public methods. Plugins work better for those.
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Vendor\Module\Api\DataInterface"
type="Vendor\Module\Model\DataImplementation" />
</config>
When Magento needs DataInterface, it instantiates DataImplementation instead.
2. Virtual Types
Virtual types create reusable configuration blueprints without generating actual PHP classes. They reduce code duplication.
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="CustomLogger" type="Psr\Log\LoggerInterface">
<arguments>
<argument name="name" xsi:type="string">custom_logger</argument>
<argument name="handlers" xsi:type="array">
<item name="system" xsi:type="object">Magento\Framework\Logger\Handler\System</item>
</argument>
</arguments>
</virtualType>
</config>
3. Type Configuration
Type configurations let you set constructor arguments, method calls, and other class-specific settings.
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Model\Product">
<arguments>
<argument name="customAttribute" xsi:type="string">custom_value</argument>
</arguments>
</type>
</config>
4. Plugins (Interceptors)
Plugins let you modify public method behavior without altering core code. They intercept method calls and run your custom code before, after, or around the original method.
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Model\Product">
<arguments>
<argument name="customAttribute" xsi:type="string">custom_value</argument>
</arguments>
</type>
</config>
Plugin Types Explained
Before Plugins
Before plugins change method arguments or add logic before the original method executes. Name your method with the before prefix.
<?php
namespace Vendor\Module\Plugin;
class ProductPlugin
{
public function beforeSetName($subject, $name)
{
// Modify the name argument
$name = strtoupper($name);
return [$name];
}
}
Return an array of modified arguments. Return null if you don't change anything.
After Plugins
After plugins modify return values. Since Magento 2.2, after plugins can access input arguments from the original method. Use the after prefix.
<?php
namespace Vendor\Module\Plugin;
class ProductPlugin
{
public function afterGetPrice($subject, $result)
{
// Add 10% to the price
return $result * 1.10;
}
}
The $result parameter holds the original return value.
Around Plugins
Around plugins wrap the entire method execution. They can run code before and after the original method. Use around plugins sparingly - they can prevent execution of other plugins if not implemented correctly.
<?php
namespace Vendor\Module\Plugin;
class ProductPlugin
{
public function aroundSave($subject, callable $proceed)
{
// Code before original method
$result = $proceed(); // Call original method
// Code after original method
return $result;
}
}
If you don't call $proceed(), the original method and other plugins won't execute.
Plugin Execution Order
The sortOrder attribute controls when plugins run. Lower numbers execute first for before and around plugins. Higher numbers execute first for after plugins.
| Plugin Type | Execution Order | Sort Order |
|---|---|---|
| Before | sortOrder 1 → 100 (ascending) | - |
| Around (before callable) | sortOrder 1 → 100 (ascending) | - |
| Original Method | - | - |
| Around (after callable) | sortOrder 100 → 1 (descending) | - |
| After | sortOrder 100 → 1 (descending) | - |
Example with three plugins (sortOrder 10, 20, 30):
1. Plugin10::beforeMethod
2. Plugin10::aroundMethod (before)
3. Plugin20::beforeMethod
4. Plugin20::aroundMethod (before)
5. Plugin30::beforeMethod
6. Plugin30::aroundMethod (before)
7. Original::method
8. Plugin30::aroundMethod (after)
9. Plugin30::afterMethod
10. Plugin20::aroundMethod (after)
11. Plugin20::afterMethod
12. Plugin10::aroundMethod (after)
13. Plugin10::afterMethod
Plugin Limitations
Plugins cannot modify final methods, final classes, non-public methods, static methods, constructors, virtual types, or objects created before the interception framework loads.
You also can't use plugins on objects instantiated with the new keyword directly.
Injectable vs Non-Injectable Objects
Injectable objects are singletons created through dependency injection using di.xml configuration. Examples: repositories, services, helpers.
Non-injectable (newable) objects require external input like database data or user input. Examples: products, orders, customers. Use factories to create these objects.
Best Practices
- Use constructor injection - Pass dependencies through class constructors instead of creating them inside methods.
- Avoid ObjectManager - Direct ObjectManager calls create hidden dependencies and bypass DI benefits. Let the DI system resolve dependencies automatically.
- Prefer plugins over preferences - Plugins keep customizations modular and reduce upgrade conflicts. Use preferences only for private/protected methods.
- Set unique sortOrder values - Prevents unpredictable behavior when multiple plugins target the same method.
- Keep classes focused - Too many constructor dependencies signals a class does too much. Break large classes into smaller, single-purpose ones.
Configuration Scope Strategy
Structure your di.xml files by scope for better performance:
- Global configurations in
etc/di.xml - Admin-specific customizations in
etc/adminhtml/di.xml - Frontend optimizations in
etc/frontend/di.xml
Magento loads configurations dynamically based on active area, modules, and theme. Area-specific files override global settings.
Summary Table
| Feature | Purpose | When to Use |
|---|---|---|
| Preferences | Map interfaces to classes | Override private/protected methods |
| Virtual Types | Reusable configuration | Multiple classes need same setup |
| Type Config | Constructor arguments | Pass values to class constructors |
| Before Plugin | Modify input | Change arguments before method runs |
| After Plugin | Modify output | Change return values |
| Around Plugin | Full control | Wrap entire method execution |
Conclusion
Factory classes form a core component of Magento 2 architecture. They handle non-injectable object creation, support dependency injection, and maintain code quality. Understanding when and how to use factories separates proficient Magento developers from beginners.
FAQs
What is the purpose of di.xml in Magento 2?
The di.xml (Dependency Injection configuration file) defines how classes and interfaces are wired together in Magento 2. It tells Magento which classes to instantiate, how to pass dependencies, and what preferences, plugins, or virtual types to apply.
Where is di.xml located?
You can find di.xml files in several scopes within a Magento module:
app/code/Vendor/Module/etc/di.xml— for global configurationapp/code/Vendor/Module/etc/frontend/di.xml— for frontend area onlyapp/code/Vendor/Module/etc/adminhtml/di.xml— for admin area only
Magento merges these configurations automatically during compilation.
How does di.xml define class preferences?
Preferences in di.xml map an interface or abstract class to a concrete implementation. This allows Magento to decide which class to instantiate when an interface is requested:
<preference for="Vendor\Module\Api\Data\ProductInterface"
type="Vendor\Module\Model\Product" />
What are constructor arguments in di.xml?
Constructor arguments let you inject specific values or class instances into objects. For example:
<type name="Vendor\Module\Model\Example">
<arguments>
<argument name="limit" xsi:type="number">10</argument>
</arguments>
</type>
This sets the $limit parameter when Example is instantiated.
How are plugins defined in di.xml?
Plugins allow you to intercept method calls before, after, or around the original method. You define them in di.xml like this:
<type name="Magento\Catalog\Model\Product">
<plugin name="custom_plugin"
type="Vendor\Module\Plugin\ProductPlugin" />
</type>
What are Virtual Types in di.xml?
Virtual Types let you reuse existing class configurations with different constructor arguments, without creating new PHP classes. Example:
<virtualType name="CustomProduct" type="Magento\Catalog\Model\Product">
<arguments>
<argument name="custom" xsi:type="boolean">true</argument>
</arguments>
</virtualType>
Can I override another module’s di.xml configuration?
Yes. Magento merges all di.xml files during compilation. If two modules define the same preference or type, the module loaded later (based on module.xml sequence) takes precedence.
How does di.xml improve Magento’s flexibility?
It decouples class dependencies, allowing developers to swap, extend, or decorate functionality without modifying core code. This supports better testability, modularity, and extensibility across the system.
Is it mandatory to use di.xml for Dependency Injection?
No. Most dependencies are automatically resolved by Magento’s Object Manager through type hinting. You only need di.xml when you want to customize or override default dependencies.
When should I modify di.xml?
Modify di.xml when you need to:
- Replace an interface implementation (using
preference). - Add or modify a plugin.
- Inject specific arguments or values into constructors.
- Create virtual types for reusable configurations.




