How to create a “HELLO WORLD” module in Magento 2?

In this blog post, we have explained how to easily create Hello World module in Magento 2. Take a note that the concept of local/ community/ core/ folders only existed in Magento 1 and we don’t use them in Magento 2.

Follow the below steps to create HELLO WORLD module

All of our custom modules in Magento 2 go under the app/code directory. The modules have a 2 part naming structure, i.e, Namespace/Module. This is so that the modules can be organized more efficiently. So, assuming our Namespace is “Codilar” and our first module will be called “HelloWorld”, the directory structure for our module is gonna be app/code/Codilar/HelloWorld/…

So now that we’ve established the directory structure, let’s make a simple module which will show “Hello World” on the content section of the page when we hit the URL "".

Ok first thing’s first. This is going to be our directory structure for the complete project

Hello, world Magento 2

So lets start with the registration.php file. app/code/Codilar/HelloWorld/registration.php


Every module must contain this file. This basically tells Magento "Please register my module, it's name is Codilar_HelloWorld, which is the Namespace and the Module name underscore separated".


Next we come to the etc/module.xml app/code/Codilar/HelloWorld/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Codilar_HelloWorld" setup_version="0.0.1"/>

This file just contains some basic information about the module. Like the module name and module version.


Now the basic files absolutely necessary for any module to work are created. Next we would create a frontend route inside our etc/frontend/routes.xml file which would tell Magento to "Forward the request to our module's controller whenever the URL is {{base_url}}/helloworld/


<?xml version="1.0"?>
<config xmlns:xsi="" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="helloworld" frontName="helloworld">
            <module name="Codilar_HelloWorld" />

Now we make the actual controller where the request would be routed. app/code/Codilar/HelloWorld/Controller/Index/Index.php

* @package magento2
* @author Codilar Technologies
* @license Open Software License v. 3.0 (OSL-3.0)
* @link
namespace Codilar\HelloWorld\Controller\Index;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\View\Result\PageFactory;

class Index extends Action {
     * @var PageFactory
    private $pageFactory;

     * Index constructor.
     * @param Context $context
     * @param PageFactory $pageFactory
    public function __construct(
        Context $context,
        PageFactory $pageFactory
        $this->pageFactory = $pageFactory;

     * Execute action based on request and return result
     * Note: Request will be added as operation argument in future
     * @return \Magento\Framework\Controller\ResultInterface|ResponseInterface
     * @throws \Magento\Framework\Exception\NotFoundException
    public function execute()
        $page = $this->pageFactory->create();
        return $page;

Now we make our layout file to handle the request app/code/Codilar/HelloWorld/view/frontend/layout/helloworld_index_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
        <referenceContainer name="content">
            <block class="Codilar\HelloWorld\Block\Hello" name="helloworld" template="Codilar_HelloWorld::hello.phtml" />

The layout file basically "references" the "content" container, and inserts our own block Codilar\HelloWorld\Block\Hellointo it. And remember, blocks and templates always come in pairs. Hence our block also uses the template Codilar_HelloWorld::hello.phtml 


Now to create our block file app/code/Codilar/HelloWorld/Block/Hello.php

 * @package     magento2
 * @author      Codilar Technologies
 * @license Open Software License v. 3.0 (OSL-3.0)
 * @link

namespace Codilar\HelloWorld\Block;

use Magento\Framework\View\Element\Template;

class Hello extends Template
    public function getText() {
        return "Hello World";

Notice that the block has a function getText() . The block's function within Magento's MVC architecture is to structure and provide data to the template which the template will then display


And now finally coming to the template file app/code/Codilar/HelloWorld/view/frontend/templates/hello.phtml

/* @var \Starlabs\HelloWorld\Block\Hello $block */
<label><?= __("Data retrieved from Block is ") ?></label>
<h1><?= $block->getText() ?></h1>

The template's job is to fetch data from it's relevant block (mentioned as an @var comment at the beginning of the template file) and display it accordingly. Ideally, the template should not be responsible for any logical decisions.


Well that's about it. Now we just run the php bin/magento setup:upgrade command from our terminal to install our new module and then open our favourite browser and type, and we should be able to see our template in action, like this.

Hello, World Magento

Well, that was all guys, on my first blog, among a series of blogs which I'm planning to release eventually which will hopefully clear all your doubts on how to work with Magento, one of the most beautiful PHP frameworks I've ever worked with, personally.

Thanks a lot for sticking through this guys. Do let me know in the comment section below about what you want my next Magento tutorial blog to be about. See you till next time!

Click here to download a zip copy of the above mentioned project


Next tutorial
- What are widgets in jQuery & how are they different from regular objects/functions?

Do let me know in the comment section below about what you want my next tutorial blog to be about. See you till next time!