Data and schema patches
A patch is a class that makes a change to the database once, when setup:upgrade runs. Patches add initial records, settings and attributes. Magento remembers applied patches and does not run them again — this way all servers end up with the same data.
Where patches live
| Module folder | What is in it |
|---|---|
Setup/Patch/Data | Data patches: adding and changing records |
Setup/Patch/Schema | Schema patches: structure changes that cannot be described in db_schema.xml |
There is no command to create one — the file is written by hand. The class name should say what it does.
app/code/Acme/Hello/
└── Setup/
└── Patch/
└── Data/
└── AddSampleReviews.php new fileA data patch
Let's add two records to the reviews table so that the /hello page has something to show:
// app/code/Acme/Hello/Setup/Patch/Data/AddSampleReviews.php
namespace Acme\Hello\Setup\Patch\Data;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
class AddSampleReviews implements DataPatchInterface
{
public function __construct(private ModuleDataSetupInterface $setup) {}
public function apply(): self
{
$this->setup->getConnection()->insertMultiple(
$this->setup->getTable('acme_hello_review'),
[
['product_id' => 1, 'author' => 'Anna', 'rating' => 5, 'content' => 'A great bag'],
['product_id' => 1, 'author' => 'John', 'rating' => 4, 'content' => 'Handy but gets dirty fast'],
],
);
return $this;
}
public static function getDependencies(): array
{
return [];
}
public function getAliases(): array
{
return [];
}
}The apply() method does the work; the other two methods are required by the interface. The getTable() method returns the table name with the prefix chosen at installation. If you added the foreign key from the schema lesson, the product with ID 1 must exist — the sample data has it.
Running
bin/magento setup:upgradeThe command applies the patch, and two reviews appear on the /hello page. On later setup:upgrade runs the patch is skipped.
How Magento remembers patches
The names of applied patches are stored in the patch_list table. To run a patch again during development, delete its row from this table and run setup:upgrade once more. Do not do this on a production server.
Execution order
If a patch needs the data of another patch, list that class in getDependencies():
// app/code/Acme/Hello/Setup/Patch/Data/AddMoreReviews.php
public static function getDependencies(): array
{
return [AddSampleReviews::class];
}Magento first applies AddSampleReviews and then this patch. Patches without dependencies run in no particular order.
A schema patch
Table structure is described by db_schema.xml, and that is almost always enough. A schema patch is needed in rare cases, for example to move data out of an old column before dropping it. It is built the same way but lives in Setup/Patch/Schema, implements Magento\Framework\Setup\Patch\SchemaPatchInterface and receives Magento\Framework\Setup\SchemaSetupInterface in its constructor.
What patches are used for
| Task | What to use |
|---|---|
| Initial records of your own tables | The connection from ModuleDataSetupInterface |
| A product or customer attribute | EavSetupFactory — covered in a later lesson |
| A configuration value | A row in the core_config_data table |
| A CMS page or block | The repositories of the Magento_Cms module |
Common mistake
A patch has already been applied, then its code was fixed and the change is expected to take effect. Magento sees the class name in patch_list and does not run it again; a colleague's server and the live site keep the old data. Write a new patch for every new change.