3.03

DB Schema & Database Tables

Master declarative schema for altering database tables using db_schema.xml, including tables, columns, indexes, foreign keys, and patches.

Why This Matters: Declarative schema revolutionized database management in Magento 2.3+. Understanding how to use db_schema.xml to alter database tables is essential for modern Magento development and exam success.

DB Schema Overview

mindmap root((db_schema.xml)) Benefits Easier upgrades Single source of truth XML based Available since 2.3 Tables Add table Modify table Remove table Columns Add column Modify column Rename column Delete column Constraints Indexes Foreign keys Primary keys Patches Data patches Schema patches Revertable

Declarative Schema Overview

Declarative schema places the structure of the database into XML. This provides the benefit of making upgrades easier in that the instructions for the upgrade come from one source.

Key Benefit: Before declarative schema, the install/upgrade scripts were very clunky and error-prone. It was sometimes difficult to determine what the final table's structure should be, as that could be determined through multiple versions of upgrades.

Availability

✅ DB Schema is available as of Magento 2.3

This configuration is found in your module's etc/db_schema.xml configuration file.

XSD Schema Location

The XSD file for db_schema.xml files is found in:

vendor/magento/framework/Setup/Declaration/Schema/etc/schema.xsd

This is where you can see all the available options.

Working with Tables

Table Element

The <table> element identifies the table that is created (or modified).

Required Attributes:

  • name: Determines the name of the table in the database
Merging: The name attribute is used for merging table configuration across multiple db_schema.xml files.

Adding a Table

To add a table to the database, specify its configuration in db_schema.xml.

etc/db_schema.xml
<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="vendor_module_entity" resource="default" engine="innodb" comment="Custom Entity Table">
        <column xsi:type="int" name="entity_id" unsigned="true" nullable="false" 
                identity="true" comment="Entity ID"/>
        <column xsi:type="varchar" name="name" nullable="false" length="255" comment="Name"/>
        <column xsi:type="timestamp" name="created_at" on_update="false" nullable="false" 
                default="CURRENT_TIMESTAMP" comment="Created At"/>
        
        <constraint xsi:type="primary" referenceId="PRIMARY">
            <column name="entity_id"/>
        </constraint>
    </table>
</schema>

Removing a Table

To remove a table, remove the table from where it is declared in db_schema.xml.

⚠️ Important: You shouldn't modify core files to remove a table.
⚠️ Common Problem: An error will occur if a module is disabled that contains the original/core declaration for a table but another module depends on the disabled module.

Working with Columns

Column Element

The <column> element configures columns to be added to the database.

Adding a Column

You can add a column into an existing Magento table. Example: adding a delivery_date column into the Magento quote table:

etc/db_schema.xml
<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="quote">
        <column xsi:type="date" name="delivery_date" nullable="true" comment="Delivery Date"/>
    </table>
</schema>

Required Column Attributes

Each column must have:

  • name: The name of the column
  • xsi:type: The type of column

Available Column Types:

Type Description Example
boolean True/False value xsi:type="boolean"
date Date value xsi:type="date"
int Integer value xsi:type="int"
text Long text xsi:type="text"
varchar Short text with length xsi:type="varchar" length="255"
timestamp Timestamp value xsi:type="timestamp"
decimal Decimal/float value xsi:type="decimal" precision="12" scale="4"

Optional Column Attributes

You can specify other attributes:

Attribute Purpose
default Determines the column's default value in MySQL
disabled Removes the column from the table
unsigned Positive and negative or just positive numbers (for integers)
padding The size of an integer column
nullable Whether the column can be NULL
identity Auto-increment column
comment Column comment in database

Renaming a Column

To rename a column, use the onCreate="migrateDataFrom(old_column_name)" attribute.

<column xsi:type="int" name="new_entity_id" unsigned="true" nullable="false" 
        onCreate="migrateDataFrom(entity_id)" comment="Entity ID"/>
How it works: This copies data from the old column to the new column. See \Magento\Framework\Setup\SchemaListener::changeColumn().
⚠️ Important: You must update your module's db_schema_whitelist.json to include both the old and the new columns.

Deleting a Column

To delete a column, use the disabled="true" attribute.

Example: Remove the coupon_code column from the quote table:

<table name="quote">
    <column xsi:type="varchar" name="coupon_code" disabled="true"/>
</table>
Note: You can use the disabled attribute to remove a column, constraint, index, or table from the database (or prevent it from being added).

Modifying a Table Added by Another Module

You would most likely be adding a column, as removing or changing the column's name will have possible serious consequences.

⚠️ Module Load Order: You must ensure that you have configured the module load order in your module's etc/module.xml file. This ensures that your module is executed after the module whose db_schema.xml file creates the original table.

Example: 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_Module">
        <sequence>
            <module name="Magento_Quote"/>
        </sequence>
    </module>
</config>

Indexes and Foreign Keys

Constraint Element

Use the <constraint> tag for indexes and foreign keys.

There are two types of constraints in schema:

  • Indexes - utilize the constraint tag with column class
  • Foreign keys - specify details as attributes in the constraint tag

Adding a Primary Key

Indexes utilize the constraint tag but have a column element to build the structure of the index.

<constraint xsi:type="primary" referenceId="PRIMARY">
    <column name="entity_id"/>
</constraint>

Adding an Index

<index referenceId="VENDOR_MODULE_ENTITY_NAME" indexType="btree">
    <column name="name"/>
</index>

Unique Index:

<constraint xsi:type="unique" referenceId="VENDOR_MODULE_ENTITY_EMAIL_UNIQUE">
    <column name="email"/>
</constraint>

Adding a Foreign Key

Foreign keys do not utilize the column tag but rather specify all their details as attributes in the constraint tag.

<constraint xsi:type="foreign" 
            referenceId="VENDOR_MODULE_ENTITY_CUSTOMER_ID_CUSTOMER_ENTITY_ID" 
            table="vendor_module_entity" 
            column="customer_id" 
            referenceTable="customer_entity" 
            referenceColumn="entity_id" 
            onDelete="CASCADE"/>

Foreign Key Attributes:

  • table: The table containing the foreign key
  • column: The column in the table
  • referenceTable: The referenced table
  • referenceColumn: The referenced column
  • onDelete: Action on delete (CASCADE, SET NULL, NO ACTION)

Data Patches

What are Data Patches?

Patches run incremental updates against the database. They perform operations that are not possible to do in the XML declaration.

Key Benefit: Once a patch is applied, the patch is stored in the patch_list table and never run again.

Generating a Data Patch

You can initialize a patch with the CLI command:

bin/magento setup:db-declaration:generate-patch Vendor_Module PatchName

Data Patch Location

Setup/Patch/Data/

Data patches must be in your module's Setup/Patch/Data directory.

Data Patch Interface

Data patches must implement \Magento\Framework\Setup\Patch\DataPatchInterface.

Three Required Methods:

  • apply(): Takes action (performs the patch)
  • getDependencies() (static): Returns an array of patches that this patch depends on
  • getAliases(): If this patch ever changes names, this returns other names for the patch

Data Patch Example

Setup/Patch/Data/AddSampleData.php
<?php
namespace Vendor\Module\Setup\Patch\Data;

use Magento\Framework\Setup\Patch\DataPatchInterface;

class AddSampleData implements DataPatchInterface
{
    private $moduleDataSetup;
    
    public function __construct(
        \Magento\Framework\Setup\ModuleDataSetupInterface $moduleDataSetup
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
    }
    
    public function apply()
    {
        $this->moduleDataSetup->getConnection()->startSetup();
        
        // Your data manipulation logic here
        $connection = $this->moduleDataSetup->getConnection();
        $tableName = $this->moduleDataSetup->getTable('vendor_module_entity');
        
        $connection->insert($tableName, [
            'name' => 'Sample Entity',
            'status' => 1
        ]);
        
        $this->moduleDataSetup->getConnection()->endSetup();
        
        return $this;
    }
    
    public static function getDependencies()
    {
        return []; // Or return array of dependent patch class names
    }
    
    public function getAliases()
    {
        return []; // Or return array of old patch names
    }
}

Revertable Patches

If you wish to make a patch able to be rolled back, implement \Magento\Framework\Setup\Patch\PatchRevertableInterface.

<?php
class RevertablePatch implements DataPatchInterface, PatchRevertableInterface
{
    public function revert()
    {
        // Logic to revert the patch (run when module is uninstalled)
    }
    
    // ... other required methods
}
When to use: This interface specifies a revert() method so you can take action when the module is being uninstalled.

Version-Based Patches

If you need to convert upgrade scripts to DB Schema and ensure the patch was only run once, use \Magento\Framework\Setup\Patch\PatchVersionInterface.

<?php
class VersionedPatch implements DataPatchInterface, PatchVersionInterface
{
    public static function getVersion()
    {
        return '2.0.1'; // Associate patch with specific version
    }
    
    // ... other required methods
}
Note: Magento's goal is to get away from version numbers being associated with database upgrades, instead relying on patches and the more intuitive DB Schema.

Schema Patches

What are Schema Patches?

Schema patches allow for intricate updates to the schema.

When to use: Almost every situation is covered in db_schema.xml. However, if you need to add a column to a table outside of Magento's control (like a custom-built application that shares the same Magento database), use a schema patch.

Creating a Schema Patch

The process is very similar to data patches with two exceptions:

  1. The patch should reside in your module's Setup/Patch/Schema directory
  2. The patch should implement \Magento\Framework\Setup\Patch\SchemaPatchInterface
Setup/Patch/Schema/

Why SchemaPatchInterface Has No Methods

Interesting Fact: You might be surprised that SchemaPatchInterface has no methods. Why would an interface extend another if it doesn't add to the original interface's functionality?
Answer: Labeling. Because you would choose to implement the DataPatchInterface or the SchemaPatchInterface, Magento knows what type of patch this is without having to rely on a directory structure.

db_schema_whitelist.json

The whitelist file contains a history of all tables, columns, keys, and constraints that have been created or modified via declarative schema.

etc/db_schema_whitelist.json

This file is auto-generated when you run:

bin/magento setup:db-declaration:generate-whitelist
⚠️ Important: You must regenerate this file whenever you modify db_schema.xml.

Exam Tips

Key Points to Remember

  • DB Schema available: Magento 2.3+
  • File location: etc/db_schema.xml
  • XSD location: vendor/magento/framework/Setup/Declaration/Schema/etc/schema.xsd
  • Add table: Specify configuration in db_schema.xml
  • Remove table: Remove from db_schema.xml
  • Add column: Add <column> element to <table>
  • Rename column: Use onCreate="migrateDataFrom(old_name)"
  • Delete column: Use disabled="true"
  • Module load order: Configure in etc/module.xml with <sequence>
  • Required column attributes: name, xsi:type
  • Column types: boolean, date, int, text, varchar, timestamp, decimal
  • Constraints: Two types - indexes and foreign keys
  • Data patches: Setup/Patch/Data/, implement DataPatchInterface
  • Schema patches: Setup/Patch/Schema/, implement SchemaPatchInterface
  • Patch methods: apply(), getDependencies(), getAliases()
  • Revertable: Implement PatchRevertableInterface, add revert() method
  • Patch storage: patch_list table
  • Whitelist: Auto-generated with setup:db-declaration:generate-whitelist

Further Reading