MAGENTO 2 Custom Database Tables

🧾 Introduction: Why Custom Tables?

Magento already has many built-in tables, but when you need to store extra data—like logs, feedback, or external API data—you’ll want your own. In Magento 2.3+, Declarative Schema makes this super easy.

In this guide, we’ll create a simple Novatra_CustomTable module with its own database table.

🛠️ Step 1: Create the Module Folder Structure

app/code/Novatra/CustomTable/
├── etc/
│   └── module.xml
├── registration.php
├── etc/db_schema.xml
├── Model/
│   └── Topic.php
├── Model/ResourceModel/
│   └── Topic.php
│   └── Topic/Collection.php
├── Api/
│   └── TopicRepositoryInterface.php
├── Repository/
│   └── TopicRepository.php

📄 Step 2: Module Declaration Files

🔧 registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Novatra_CustomTable',
    __DIR__
);

Try It Now

🔧 etc/module.xml

🧱 Step 3: Create Table Using Declarative Schema

🔧 etc/db_schema.xml

💡 Step 4: Create Model and ResourceModel

🔧 Model/Topic.php

<?php
namespace Novatra\CustomTable\Model;

use Magento\Framework\Model\AbstractModel;

class Topic extends AbstractModel
{
    protected function _construct()
    {
        $this->_init(\Novatra\CustomTable\Model\ResourceModel\Topic::class);
    }
}

Try It Now

🔧 ResourceModel/Topic.php

<?php
namespace Novatra\CustomTable\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Topic extends AbstractDb
{
    protected function _construct()
    {
        $this->_init('novatra_topic', 'topic_id');
    }
}

Try It Now

🔧 ResourceModel/Topic/Collection.php

<?php
namespace Novatra\CustomTable\Model\ResourceModel\Topic;

use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;

class Collection extends AbstractCollection
{
    protected function _construct()
    {
        $this->_init(
            \Novatra\CustomTable\Model\Topic::class,
            \Novatra\CustomTable\Model\ResourceModel\Topic::class
        );
    }
}

Try It Now

📦 Step 5: Add Repository (Recommended)

🔧 Api/TopicRepositoryInterface.php

<?php
namespace Novatra\CustomTable\Api;

use Novatra\CustomTable\Model\Topic;

interface TopicRepositoryInterface
{
    public function save(Topic $topic);
    public function getById($id);
    public function delete(Topic $topic);
}

Try It Now

🔧 Repository/TopicRepository.php

<?php
namespace Novatra\CustomTable\Repository;

use Novatra\CustomTable\Model\Topic;
use Novatra\CustomTable\Model\ResourceModel\Topic as TopicResource;
use Novatra\CustomTable\Api\TopicRepositoryInterface;
use Magento\Framework\Exception\NoSuchEntityException;

class TopicRepository implements TopicRepositoryInterface
{
    protected $resource;
    protected $topicFactory;

    public function __construct(
        TopicResource $resource,
        \Novatra\CustomTable\Model\TopicFactory $topicFactory
    ) {
        $this->resource = $resource;
        $this->topicFactory = $topicFactory;
    }

    public function save(Topic $topic)
    {
        $this->resource->save($topic);
        return $topic;
    }

    public function getById($id)
    {
        $topic = $this->topicFactory->create();
        $this->resource->load($topic, $id);
        if (!$topic->getId()) {
            throw new NoSuchEntityException(__('Topic with ID "%1" does not exist.', $id));
        }
        return $topic;
    }

    public function delete(Topic $topic)
    {
        $this->resource->delete($topic);
        return true;
    }
}

Try It Now

🧪 Step 6: Run Setup & Test

bin/magento module:enable Novatra_CustomTable
bin/magento setup:upgrade

Try It Now

✅ Summary

You’ve successfully:

  • Created a Magento 2 custom module
  • Built a custom database table with declarative schema
  • Added a model, resource model, and repository
  • Ran setup and verified table creation

Now you’re ready to use custom tables in real projects!