logo
Developer writing code

Development

Magento 2 Developer Guide: Architecture Deep Dive

Omkar RahiOmkar Rahi·2026-03-18·10 min read

Magento 2 Module Structure

Every piece of Magento functionality lives in a module. A minimal module needs just two files:

app/code/Vendor/ModuleName/
├── etc/
│   └── module.xml
└── registration.php
<!-- etc/module.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_ModuleName" setup_version="1.0.0"/>
</config>
// registration.php
use Magento\Framework\Component\ComponentRegistrar;
 
ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Vendor_ModuleName',
    __DIR__
);

Dependency Injection

Magento 2 uses constructor injection exclusively. You never instantiate objects with new — the Object Manager handles it.

namespace Vendor\ModuleName\Model;
 
use Magento\Catalog\Api\ProductRepositoryInterface;
use Psr\Log\LoggerInterface;
 
class ProductService
{
    public function __construct(
        private readonly ProductRepositoryInterface $productRepository,
        private readonly LoggerInterface $logger,
    ) {}
 
    public function getProduct(int $id): \Magento\Catalog\Api\Data\ProductInterface
    {
        return $this->productRepository->getById($id);
    }
}

Plugins (Interceptors)

Plugins let you modify the behavior of any public method without overriding the class — Magento's most powerful extensibility mechanism.

namespace Vendor\ModuleName\Plugin;
 
class ProductNamePlugin
{
    public function afterGetName(
        \Magento\Catalog\Model\Product $subject,
        string $result
    ): string {
        return strtoupper($result); // Transforms product name to uppercase
    }
}

Register it in etc/di.xml:

<type name="Magento\Catalog\Model\Product">
    <plugin name="vendor_module_product_name" type="Vendor\ModuleName\Plugin\ProductNamePlugin"/>
</type>

The Request Lifecycle

  1. index.php bootstraps the application
  2. FrontController routes the request to the matching router
  3. The matched Action class renders a ResultInterface
  4. Layout XML determines which blocks are rendered
  5. Blocks fetch data from Models/Repositories and output HTML

Events and Observers

For loose coupling, dispatch events instead of calling other modules directly:

$this->eventManager->dispatch('vendor_order_placed', ['order' => $order]);
<!-- etc/events.xml -->
<event name="vendor_order_placed">
    <observer name="send_confirmation" instance="Vendor\ModuleName\Observer\SendConfirmation"/>
</event>

Running Commands in MagentoEnv

All bin/magento commands are available in the environment terminal. Changes to DI configuration require recompilation:

bin/magento setup:di:compile
bin/magento cache:clean config full_page