09 Aug 2026 · 1 min read
Build a real Magento 2 module end-to-end
Scaffold a Magento 2 module the right way — registration, di.xml, a model + resource, a controller, and a CLI command on a real local stack.
Theory is cheap; let's build. This post scaffolds a small but complete Magento 2 module — the same shape every real extension follows — and verifies it on a real stack.
1. Registration
app/code/Ddt/Example/registration.php calls ComponentRegistrar::register(...); composer.json declares the autoload path. Without these, Magento never sees the module.
2. DI and a service
etc/di.xml wires a Service class. Inject interfaces, not concretes, so the module stays upgrade-safe (per the code best-practices post). No Preference for core classes.
3. Model + resource model
For custom data, define a Model, a ResourceModel, and a Collection extending the framework base classes. Never query the DB directly from a controller — go through the resource layer or a repository.
4. A controller (or a CLI command)
Prefer a CLI command (bin/magento ddt:example) for admin/maintenance tasks; it's easier to test and doesn't need a route. For a storefront action, a front controller with a layout works, but reach for it sparingly.
5. Verify it
Drop the module in, then from govard shell:
bin/magento setup:upgrade
bin/magento ddt:example
Running on a production-shaped local stack (Nginx, PHP, MariaDB, Redis via Govard) means the module's wiring is validated against the environment you'll ship, not a hand-rolled dev box.
Where this fits
This is the practical payoff of the architecture and code-quality posts. A module built this way passes the audit checklist and survives the upgrade pipeline discussed earlier.
Next in this series: Open Source vs Commerce — when to upgrade —
/blog/magento2-opensource-vs-commerce