Applying Declarative Schema Changes in Magento 2.4+
Step‑by‑step guide to add a database column using db_schema.xml, run setup:upgrade, verify the change, and recover if needed.
14 Jun 2026, 08:09 UTC

Desired outcome
Apply a repeatable, version‑controlled database change (e.g., add a column to a custom table) using Magento’s declarative schema mechanism. The change is defined in etc/db_schema.xml, tracked by db_schema_whitelist.json, and applied by running bin/magento setup:upgrade without manual SQL.
Prerequisites
- Magento Open Source or Commerce 2.4+ installed with declarative schema support.
- A custom module (e.g.,
Vendor_Custom) withregistration.phpandetc/module.xmlalready present. - SSH access to the web server and sufficient privileges to run Magento CLI commands.
- Database user with
ALTER,CREATE, andDROPpermissions. - A recent database backup (or a snapshot) taken before starting.
- Ability to put the store into maintenance mode during the upgrade window.
Focused procedure
- Place the instance in maintenance mode (optional but recommended for production):
bin/magento maintenance:enable - Define the schema change in the module’s
etc/db_schema.xml. Example: add a nullable VARCHAR column namedcustom_fieldto thesales_ordertable.<?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">
</schema> - Bump the module version in
etc/module.xmlso Magento knows a new schema version exists. If the current version is1.0.0, change it to1.0.1:<module name="Vendor_Custom" setup_version="1.0.1"> <sequence> <module name="Magento_Sales"></module> </sequence> </module> - Run the upgrade to apply the declarative change:
The command should output a line similar to:bin/magento setup:upgradeSchema creation/updates:followed by your module name. - Compile DI and flush caches (required after schema changes):
bin/magento setup:di:compile bin/magento cache:flush - Disable maintenance mode if you enabled it:
bin/magento maintenance:disable
Expected checks
- Review the console output of
setup:upgradefor a line indicating your module’s schema update was applied. - Inspect the database directly (e.g., via MySQL client) to confirm the column exists:
Expect a row withSHOW COLUMNS FROM sales_order LIKE 'custom_field';Field=custom_fieldandNull=YES. - Verify that
app/etc/db_schema_whitelist.json(orvar/db_schema_whitelist.jsonin developer mode) now contains an entry for the new column under thesales_ordertable. - Check
var/log/system.logandvar/log/exception.logfor any errors triggered during or after the upgrade. - Perform a basic storefront and admin workflow that touches the sales order (e.g., view an order) to ensure no fatal errors appear.
- Re‑run
setup:upgradeon a second, identical environment to confirm the change is idempotent (no further schema alterations reported).
Recovery options
If the upgrade produces unexpected results or you need to revert the change:
- Restore the database from the backup taken before starting. This is the safest rollback for any unintended data impact.
- Revert the module version in
etc/module.xmlback to the previous value (e.g.,1.0.0) and runsetup:upgradeagain. Declarative schema will attempt to return the schema to the prior version, dropping the added column. - Remove the column definition from
etc/db_schema.xml, keep the module version unchanged, and runsetup:upgrade. The declarative engine will detect the mismatch and drop the column. - If the module is no longer needed, disable it via
bin/magento module:disable Vendor_Customand runsetup:upgradeto clean up any remaining schema artifacts.
Limitations and practical verification
Declarative schema behavior varies between Magento 2.3, 2.4, and Commerce editions; the steps above assume 2.4+ where full support exists. Always test the procedure on a staging clone first. Large schema changes can cause table locks on high‑traffic stores; schedule the upgrade during low‑traffic periods and consider using maintenance mode to avoid concurrent writes.
To verify the change in an automated way, you can add a simple script that checks the column’s presence and logs success or failure:
#!/bin/bash
DB_NAME="magento"
TABLE="sales_order"
COLUMN="custom_field"
if mysql -N -e "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='$DB_NAME' AND TABLE_NAME='$TABLE' AND COLUMN_NAME='$COLUMN';" | grep -q "^$COLUMN$"; then
echo "Column $COLUMN exists."
else
echo "Column $COLUMN missing."
exit 1
fi
Run this script after setup:upgrade; a zero exit status confirms the column is present.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.