With the release of Magento 2.3, the platform introduced a revolutionary way to handle database changes: the Declarative Schema. If you have been working with Magento for a long time, you likely remember the days of InstallSchema and UpgradeSchema scripts. While effective, those PHP-based scripts were often difficult to maintain, especially when dealing with complex versioning and rollbacks.

In this guide, you will learn how to implement the declarative schema in your custom Magento modules. We will cover everything from creating your first table to handling complex data migrations and column renaming. By moving to this approach, you ensure your module is compatible with modern Adobe Commerce standards and simplify your development workflow.

Understanding the Declarative Schema Approach

Declarative schema allows you to define the final desired state of your database in an XML file. Instead of writing scripts that describe how to change the database (e.g., "add this column, then change that index"), you simply describe what the database should look like. Magento then compares the XML file to the current database structure and automatically generates the necessary SQL queries to bridge the gap.

This approach is idempotent, meaning you can run it multiple times without side effects, and it makes version control much cleaner as you can see the entire table structure in a single file rather than across dozens of upgrade scripts.

Step 1: Creating the db_schema.xml File

The heart of the declarative schema is the db_schema.xml file. This file must be placed in the etc directory of your custom module.

Let’s look at a practical example. Suppose you are building a module named RH_Helloworld. You would create the file at app/code/RH/Helloworld/etc/db_schema.xml. Here is a standard configuration for a custom table:

<?xml version="1.0"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved. cut
 * See COPYING.txt for license details.
 */
-->
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="rh_helloworld" resource="default" engine="innodb" comment="RH Helloworld">
        <column xsi:type="smallint" name="id" padding="6" unsigned="false" nullable="false" identity="true" comment="ID"/>
        <column xsi:type="varchar" name="author_name" nullable="false" length="25" comment="Name"/>
        <column xsi:type="varchar" name="email" nullable="false" length="25" comment="Email"/>
        <column xsi:type="varchar" name="description" nullable="false" length="255" comment="Descrition"/>
        <constraint xsi:type="primary" referenceId="PRIMARY">
            <column name="id"/>
        </constraint>
    </table>
</schema>

Breaking Down the XML Elements

  • <table>: This tag defines the table name, the database resource (usually default), and the engine (usually innodb).
  • <column>: This defines the individual fields. Note the xsi:type attribute, which specifies the data type (e.g., varchar, int, timestamp, decimal).
  • <constraint>: Use this for primary keys, foreign keys, and unique constraints. The referenceId is a unique identifier for the constraint within the database.

Step 2: Advanced Data Types and Multiple Tables

You aren't limited to simple strings and integers. Magento's declarative schema supports a wide range of MySQL types including decimals for pricing and timestamps for logging. You can also define multiple tables within a single XML file.

Consider this more complex example involving a book database:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="books_data" resource="default" engine="innodb" comment="Book Table">
        <column xsi:type="smallint" name="id" padding="6" unsigned="false" nullable="false" identity="true" comment="BOOK ID"/>
        <column xsi:type="varchar" name="book_name" nullable="false" length="255" comment="Book Name"/>
        <column xsi:type="int" name="author" unsigned="true" nullable="true" identity="false" default="" comment="Author"/>
        <column xsi:type="varchar" name="isbn_no" nullable="true" comment="ISBN No"/>
        <column xsi:type="timestamp" name="publish_date" on_update="false" nullable="false" default="CURRENT_TIMESTAMP" comment="Publish Date"/>
        <column xsi:type="varchar" name="language" nullable="true" comment="Language"/>
        <column xsi:type="decimal" name="mrp" scale="4" precision="12" unsigned="false" nullable="false" default="0" comment="MRP"/>
        <constraint xsi:type="primary" name="PRIMARY">
            <column name="id"/>
        </constraint>
    </table>

    <table name="author_data" resource="default" engine="innodb" comment="Author Table">
        <column xsi:type="smallint" name="id" padding="6" unsigned="false" nullable="false" identity="true" comment="Author ID"/>
        <column xsi:type="varchar" name="author_name" nullable="false" length="255" comment="Author Name"/>
        <column xsi:type="varchar" name="author_email" nullable="false" length="255" comment="Author Email"/>
        <column xsi:type="varchar" name="affliation" nullable="false" length="255" comment="Affliation"/>
        <column xsi:type="int" name="age" unsigned="true" nullable="true" identity="false" default="" comment="Age"/>
        <constraint xsi:type="primary" name="PRIMARY">
            <column name="id"/>
        </constraint>
    </table>
</schema>

Step 3: Generating the Whitelist File

One of the security features of the declarative schema is the whitelist. To prevent accidental data loss, Magento will not drop columns or tables unless they are explicitly mentioned in a db_whitelist_schema.json file.

After you have created or modified your db_schema.xml, you must generate this whitelist file using the following CLI command:

php bin/magento setup:db-declaration:generate-whitelist --module-name=Vendor_Module

Replace Vendor_Module with your actual module name (e.g., RH_Helloworld). This will create a JSON file in your etc folder. This file is a snapshot of your database state and should be committed to your version control system.

Step 4: Applying the Changes

Once the XML is defined and the whitelist is generated, applying the changes is as simple as running the standard Magento upgrade command:

php bin/magento setup:upgrade

Magento will parse your XML, check it against the whitelist and the current database, and execute the required DDL (Data Definition Language) statements.

Modifying Existing Tables

The declarative schema makes it incredibly easy to modify existing structures without writing complex migration logic.

Renaming a Column

If you need to rename a column while preserving the data, you can use the onCreate attribute. This tells Magento to migrate data from the old column name to the new one:

<column xsi:type="varchar" name="customer_email" onCreate="migrateDataFrom(email)" on_update="false" nullable="false" default="" comment="Customer Email"/>

Dropping a Table or Column

To remove a table, you can either delete the entire <table /> node from your XML or set the disabled attribute to true. Using disabled="true" is often safer as it allows you to keep a record of the table's previous existence in your code:

<table name="rh_helloworld" resource="default" engine="innodb" comment="RH Helloworld" disabled="true">
    <!-- Columns here -->
</table>

Frequently Asked Questions

Can I still use InstallSchema scripts in Magento 2.3+?

Yes, Magento 2.3 and later versions are backward compatible with script-based schemas. However, it is highly recommended to use the declarative approach for all new development as it is the current industry standard for Adobe Commerce.

What happens if I forget to generate the whitelist file?

If you add a new table, Magento will likely create it. However, if you try to delete a column or rename a table without updating the db_whitelist_schema.json, Magento will ignore those specific changes to protect your data. Always regenerate the whitelist after modifying your schema.

How do I handle data migration (DML)?

Declarative schema is strictly for structural changes (DDL). For inserting or updating actual data (Data Manipulation Language), you should still use DataPatch scripts, which provide a reliable way to handle data updates in a declarative environment.

Wrapping Up

Implementing declarative schema in your custom Magento modules is a significant step toward cleaner, more maintainable code. By defining your database structure in db_schema.xml and using the whitelist generation tool, you reduce the risk of migration errors and make your module easier for other developers to understand.

Remember to always run the whitelist generation command before running setup:upgrade and keep your XML files organized. With these practices, you'll be mastering Magento database management in no time.