What is HMVC in CodeIgniter 4?

             CodeIgniter 4 HMVC applications are built using the HMVC Architecture Pattern, which allows for greater modularity and flexibility. This architecture, based on the traditional MVC pattern, enables the development of independent modules, each containing its own Model, View, and Controller components. This modular structure simplifies maintenance and encourages code reuse across different parts of the application.

CodeIgniter 4 HMVC: How to Build Modular Applications (Step-by-Step Guide)

Table Of Content

1 Prerequisites

  • PHP 8.1+
  • Composer
  • MySQL/MariaDB
  • basic CodeIgniter 4 knowledge.

2 Introduction

In this article, we explore the CodeIgniter 4 HMVC application in detail. We’ll walk through how to set up HMVC integration in CodeIgniter 4, and look at examples of applications built using the CodeIgniter 4 HMVC Architecture Pattern.

3 Install a Fresh CodeIgniter 4 Project

3.1 Install Codeigniter 4 Project

To get started, ensure that you have Composer installed on your computer. Use the following command to install a new CodeIgniter project:

composer create-project codeigniter4/appstarter ci4-hmvc-app

Then, navigate to your project directory:

cd ci4-hmvc-app

3.2 Configure MySql Database

After successful installation, configure your database by modifying the .env file. Input your database credentials as shown below:

database.default.hostname = localhost
database.default.database = codeigniter_4
database.default.username = root
database.default.password = 
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306

4 Create the Modules Folder and Blog Module Structure

To set up HMVC integration in CodeIgniter 4, create a new directory called Modules under the app folder. For instance, you can create a module named Blog, containing controllers, models, and views subdirectories.

app/
└── Modules/
    └── Blog/
        ├── Config/
        ├── Controllers/
        ├── Models/
        └── Views/

You can create these directories manually or via your IDE.

5  Register the Module Namespace

Edit app/Config/Autoload.php and update the $psr4 array to include the Blog module:

<?php
namespace Config;

use CodeIgniter\Config\AutoloadConfig;

class Autoload extends AutoloadConfig
{
    public array $psr4 = [
        APP_NAMESPACE => APPPATH, // For custom app namespace
        'Config'      => APPPATH . 'Config',
        'Modules\Blog' => ROOTPATH . 'Modules/Blog', // Add this for the Blog module
    ];

    // ... (rest of the file remains unchanged)
}

6 Create Migration and Model

Create a migration for the posts table to store your data. Also, create a model PostModel. Run this command to generate the model:
Create a migration file by running:

php spark make:migration AddPost

This creates a file like app/Database/Migrations/2026-01-26-061500_AddPost.php (timestamp will vary). Update it as follows:

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class AddPost extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id' => [
                'type'           => 'BIGINT',
                'constraint'     => 255,
                'unsigned'       => true,
                'auto_increment' => true
            ],
            'title'       => [
                'type'       => 'VARCHAR',
                'constraint' => '255',
            ],
            'description' => [
                'type' => 'longtext'
            ],
            'created_at'  => [
                'type' => 'TIMESTAMP',
                'null' => true
            ],
            'updated_at'  => [
                'type' => 'TIMESTAMP',
                'null' => true
            ],
        ]);
        $this->forge->addPrimaryKey('id');
        $this->forge->createTable('posts');
    }

    public function down()
    {
        $this->forge->dropTable('posts');
    }
}

Use the following command to run the migration to update your database.

php spark migrate

Run this command to generate the model:

php spark make:model PostModel --suffix --namespace "Modules\Blog"

This creates app/Modules/Blog/Models/PostModel.php. Update it as follows:

<?php
namespace Modules\Blog\Models;

use CodeIgniter\Model;

class PostModel extends Model
{
    protected $table            = 'posts';
    protected $primaryKey       = 'id';
    protected $useAutoIncrement = true;
    protected $returnType       = 'array';
    protected $useSoftDeletes   = false;
    protected $protectFields    = true;
    protected $allowedFields    = ['title', 'description'];

    protected bool $allowEmptyInserts = false;
    protected bool $updateOnlyChanged = true;

    protected array $casts = [];
    protected array $castHandlers = [];

    // Dates
    protected $useTimestamps = false;
    protected $dateFormat    = 'datetime';
    protected $createdField  = 'created_at';
    protected $updatedField  = 'updated_at';
    protected $deletedField  = 'deleted_at';

    // Validation
    protected $validationRules      = [];
    protected $validationMessages   = [];
    protected $skipValidation       = false;
    protected $cleanValidationRules = true;

    // Callbacks
    protected $allowCallbacks = true;
    protected $beforeInsert   = [];
    protected $afterInsert    = [];
    protected $beforeUpdate   = [];
    protected $afterUpdate    = [];
    protected $beforeFind     = [];
    protected $afterFind      = [];
    protected $beforeDelete   = [];
    protected $afterDelete    = [];
}

7 Create the Blog Controller

Run this command to generate the controller:

php spark make:controller BlogController --suffix --namespace "Modules\blog"

This creates app/Modules/Controllers/BlogController.php. Update it as follows:

<?php
namespace Modules\Blog\Controllers;

use App\Controllers\BaseController;
use Modules\Blog\Models\PostModel;

class BlogController extends BaseController
{
    private $postModel;

    public function __construct()
    {
        $this->postModel = new PostModel();
    }

    public function index()
    {
        $data = [
            'posts' => $this->postModel->findAll(),
        ];
        return view('post', $data);
    }
}
?>

8 Create the Post View

Create app/Modules/Blog/Views/post.php with the following content:


 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>CodeIgniter 4 Implementing the HMVC Architecture Pattern</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
    <link rel="stylesheet" href="https://mdbcdn.b-cdn.net/wp-content/themes/mdbootstrap4/docs-app/css/dist/mdb5/standard/core.min.css">
    <link rel='stylesheet' id='roboto-subset.css-css'
          href='https://mdbcdn.b-cdn.net/wp-content/themes/mdbootstrap4/docs-app/css/mdb5/fonts/roboto-subset.css?ver=3.9.0-update.5'
          type='text/css' media='all' />
</head>
<body>

<div class="container-fluid">
    <div class="row">
        <div class="col-md-3"></div>
        <div class="col-md-6 mb-4">
            <div class="card mb-4">
                <div class="card-header py-3">
                    <h5 class="mb-0">CodeIgniter 4 Implementing the HMVC Architecture Pattern</h5>
                </div>
                <div class="card-body">
                    <?php foreach ($posts as $post): ?>
                        <h2><?= esc($post['title']) ?></h2>
                        <p><?= esc($post['description']) ?></p>
                    <?php endforeach; ?>
                </div>
            </div>
        </div>
        <div class="col-md-3"></div>
    </div>
</div>

<script type="text/javascript"
        src="https://mdbcdn.b-cdn.net/wp-content/themes/mdbootstrap4/docs-app/js/dist/mdb5/standard/core.min.js"></script>
</body>
</html>

9 Define Module Routes

Create app/Modules/Blog/Config/Routes.php with:

<?php
$routes->group('blog', ['namespace' => 'Modules\Blog\Controllers'], static function ($routes) {
    $routes->get('/', 'BlogController::index');
});

Now, edit app/Config/Routes.php to dynamically load routes from all modules. Append this at the end of the file (after the default routes):



$modules_path = ROOTPATH . 'Modules/';
$modules = scandir($modules_path);

foreach ($modules as $module) {
	if ($module === '.' || $module === '..') {
		continue;
	}

	if (is_dir($modules_path) . '/' . $module) {
		$routes_path = $modules_path . $module . '/Config/Routes.php';
		if (file_exists($routes_path)) {
			require $routes_path;
		} else {
			continue;
		}
	}
}

This scans the Modules/ folder and includes each module's Routes.php automatically.

10 Folder Structure

Your project should look like this (simplified):

ci4-hmvc-app/
├── app/
│   ├── Config/
│   │   ├── Autoload.php  # Updated with namespace
│   │   └── Routes.php    # Updated with dynamic module loader
│   ├── Database/
│   │   └── Migrations/
│   │       └── 2026-01-26-061500_AddPost.php  # Timestamp varies
│   ├── Modules/
│   │   └── Blog/
│   │       ├── Config/
│   │       │   └── Routes.php
│   │       ├── Controllers/
│   │       │   └── BlogController.php
│   │       ├── Models/
│   │       │   └── PostModel.php
│   │       └── Views/
│   │           └── post.php
│   └── ... (other default files)
├── .env  # Database config
└── ... (vendor, writable, etc.)

11 Run Web Server to Test the App

Run the following command to start the server and test the app:

php spark serve

Open your browser and go to: http://localhost:8080/blog

You'll see the page title and an empty list (since no posts yet).

Insert Sample Data for Testing (Optional)

To add a test post, you can run a temporary script or use a database tool like phpMyAdmin. Here's a quick PHP snippet you can add to a temporary route or run via php spark shell:


$db = \Config\Database::connect();
$db->table('posts')->insert([
    'title' => 'First HMVC Post',
    'description' => 'This is a test description for HMVC in CodeIgniter 4.',
]);

Refresh http://localhost:8080/blog, and the post should appear.

12 Conclusion

That’s all you need to implement the HMVC Architecture Pattern in CodeIgniter 4. Now, you can build modular, scalable applications with ease!
Revathi M - PHP and CodeIgniter Developer

Written by Revathi M

PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel

Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.

Frequently Asked Questions

HMVC is an extension of the MVC pattern that allows modular, reusable, and independent components (modules) each with their own Models, Views, and Controllers.

You need PHP 8.2 or higher, Composer installed, and a MySQL database.

Run `composer create-project codeigniter4/appstarter ci-4-hmvc-app`, then `cd ci-4-hmvc-app`.

Edit the `.env` file and set database credentials like `database.default.hostname`, `database.default.database`, `username`, `password`, `DBDriver = MySQLi`, and `port`.

Create a `Modules` directory inside the `app/` folder, then add subdirectories like `Controllers`, `Models`, and `Views` for each module (e.g., `Blog`).

In `app/Config/Autoload.php`, add to the `$psr4` array: 'Modules\\Blog' => ROOTPATH . 'Modules/Blog'.

Run php spark make:model PostModel --suffix --namespace `Modules\\Blog`, then configure the model (table, allowed fields, etc.).

Run `php spark make:migration AddPost`, define the table schema (e.g., `posts` with id, title, description), then run `php spark migrate`.

Run php spark make:controller BlogController --suffix --namespace `Modules\\Blog`, then fetch data from the model and pass to the view.

Place the view file (e.g., `post.php`) in `app/Modules/Blog/Views/` and loop through data to display it.

Create a `Routes.php` file inside the module's `Config/` directory with grouped routes and namespace. Then, in the main `app/Config/Routes.php`, dynamically include all module routes using `scandir` and `require`.

Common causes: incorrect namespace registration in `Autoload.php`, wrong file paths, or forgetting to use the full namespace when instantiating models/controllers.

No, it uses only native CodeIgniter 4 features like namespaces, autoloading, and dynamic route inclusion.

Start the server with `php spark serve`, then visit `http://localhost:8080/blog` (or your module route).