Backup
yui/craft-backup adds a standalone backup and restore workflow for a store running yui/craft-plugin. It exports store data (settings, catalog, customers, orders, and more) into a single compressed file that an admin can download, and can restore that data back into the same or another environment.
Use it for point-in-time snapshots before a risky change (bulk price update, catalog import, plugin upgrade) or to move store data between environments.
What it does
- Adds a Backup section to the Craft control panel with a Dashboard page (create, list, download, delete, and restore backups) and a Settings page (retention configuration).
- Packages the exported data as a single compressed
.json.gzfile, stored understorage/yui/backups/on the server. - Lets an admin restore from a stored backup, or from a manually uploaded/pasted backup file — either as a dry run (report what would change, no writes) or an execute run.
- Keeps a restore history log (source, mode, conflict policy, status, duration, result summary, downloadable log file) for every restore attempt.
- Provides a console command to create a backup from a cron job or deploy script.
- Prunes old backups and restore history on demand (or automatically after each backup, if enabled).
Where admins work with this plugin
In Craft CP, open the Backup section (yui-backup) from the primary navigation. It has two pages:
- Dashboard (
yui-backup/dashboard) — the main working page: create a backup, see the list of existing backups, download or delete one, run a restore (dry run or execute), do a manual restore from an uploaded file, and browse restore history. - Settings (
yui-backup/settings) — retention configuration. See Settings.
See Release Notes for version history.
There is no separate "Backups" nav item — the CP route yui-backup/backups exists and renders the same page as the Dashboard, but only the Dashboard link appears in the sidebar.
What gets backed up
A backup is grouped into domains — settings and database tables that belong together. yui/craft-backup ships the domain list for the core yStore data model:
| Domain | Contents |
|---|---|
settings | Plugin settings collected from every plugin that listens for the collect-settings event. |
stores | Stores, currencies, countries, tax rates and tax category groups. |
catalog | Products, product types, product data/variants/mappings, prices and price history, catalog rules. |
customers | Customers, addresses, subscribers, blacklist, social accounts. |
orders | Orders, order items, invoices, order history/statuses, quotes. |
shipping | Shipping methods, fees, zones, rules, table rates, delivery time slots/holidays/exclusions/reservations. |
payments | Payment methods and payment transactions. |
marketing | Coupons, gift cards, wishlists, cart shares, watchdog, email templates, search terms. |
automation | Flows, flow runs, flow logs, scheduled actions, credentials, audit trails. |
system | Core storage, notes, report data. |
This list is not hardcoded in PHP — it is defined in backups.xml files, and any Composer package can ship its own backups.xml to register additional domains or tables. At backup time, the plugin scans every installed package under vendor/ for a file named backups.xml and merges all domain definitions it finds. When you create a backup without selecting specific domains, every registered domain is included.
How a backup and restore works
- An admin clicks Create Backup on the Dashboard. The underlying
BackupService::createBackup()accepts a$domainsarray to scope a backup to specific domains, but neither the Dashboard button nor a console command exposes this today — every backup created through the UI includes all registered domains. Domain-scoped backups currently require calling the service directly (e.g. from a custom console command or plugin code). - The plugin builds a JSON payload (
schemaVersion,pluginVersion,craftVersion,generatedAt,environment,entities), computes a SHA-256 checksum over it, gzip-compresses it, and saves it tostorage/yui/backups/backup-<timestamp>-<random>.json.gz. ABackupRecordrow tracks the file, checksum, domains, record count, and size. - To restore, the admin picks a stored backup (or uploads/pastes a manual payload) and chooses Dry Run or Restore, plus a conflict policy.
- The plugin validates the payload's schema version and checksum before touching anything. If validation fails, the restore is rejected with no changes made.
- The plugin fires an internal event with the parsed entities; the actual restoration logic (upserting rows, applying settings) is implemented by
yui/craft-plugin's backup restore handler, not byyui/craft-backupitself — see Requirements. - Every restore attempt (dry run or execute, stored or manual) is logged as a
BackupRestoreRecordwith a downloadable JSON log file, visible in the Restore History table on the Dashboard.
Conflict policies
When restoring, choose how the restore should handle rows that already exist:
- Overwrite (upsert) — update existing rows, insert new ones. Default.
- Skip on conflict — leave existing rows untouched, only insert rows that don't already exist.
- Fail fast — stop the restore at the first conflict instead of silently choosing a resolution.
Always run Dry Run first with your intended conflict policy and review the result summary before running the real restore — a dry run reports what would happen without writing anything, and an execute run wraps its writes in a database transaction that rolls back if the restore handler throws.
Requirements
- Craft CMS 5 project.
yui/craft-coreversion 1, for the underlyingBackupService, records, and migrations.yui/craft-plugin, for the domain definitions this plugin ships (catalog, orders, customers, etc.) to actually mean anything, and for the restore handler that performs the writes. Withoutyui/craft-pluginactive,yui-backupstill installs and its CP pages still work, but a backup would only contain domains registered by whatever other packages ship abackups.xml, and a restore'sEVENT_RESTORE_ENTITIESwould have no listener to act on it — the restore would report success with an empty summary rather than actually writing anything.- Composer access to
https://packages.yui.sk/.
Installation
composer config repositories.yui composer https://packages.yui.sk/
composer require yui/craft-backup
php craft plugin/install yui-backup
php craft migrate/all
Migrations create the yui_backups and yui_backup_restores tables used by yui/craft-core's BackupService.
Backup file format
A backup file is a gzip-compressed JSON document:
{
"schemaVersion": "1.0.0",
"pluginVersion": "...",
"craftVersion": "5.x.x",
"generatedAt": "2026-07-27T12:00:00+00:00",
"environment": "production",
"entities": { "settings": {...}, "stores": [...], "...": "..." },
"checksum": "sha256:..."
}
The checksum is computed over the payload with the checksum field itself excluded, so any manual edit to a downloaded file invalidates it and the restore is rejected on validation. Manual restore accepts both raw .json and compressed .json.gz/.gz uploads, or pasted JSON text.
Console command
php craft yui-backup/backups/create
Creates a backup covering every registered domain. Prints the new backup's ID and file name, or an error message and a non-zero exit code on failure. Useful for a scheduled cron job or a pre-deploy step; there is currently no console command for pruning or restoring.
Security notes
- Every backup and restore action, including view, requires the current user to be a Craft admin, or to hold the matching
yui-backup:backups:view/:create/:download/:restore/:deletepermission. These permission strings exist in code but are not yet registered in Craft's Settings → Users → Permissions UI, so in practice only admins can use this plugin today. - The whole feature can be disabled per environment by setting
YUI_BACKUPS_ENABLED=false(also accepts0,off,no) — every controller action then throws a 403, regardless of user permissions. - Manually uploaded restore files are limited to 10 MB and must have a
.jsonor.gzextension; the content is still schema/checksum-validated before use. - A backup file contains raw store data (customer records, order data, etc.) in compressed but unencrypted form. Treat downloaded backup files with the same care as a database dump — store them somewhere access-controlled, not in a public or shared location.
Developer / API reference
yui\craftcore\services\BackupService (bundled with yui/craft-core)
The actual backup/restore engine lives in craft-core, not in this plugin. yui/craft-backup is a thin CP/console layer over it. Key methods: createBackup(array $domains = []), getBackups(), getBackupById(), deleteBackup(), pruneBackups(), restoreFromStoredBackup(), restoreManualPayload(), decodePayloadString(), pruneRestoreHistory().
Events
BackupService::EVENT_RESTORE_ENTITIES(\yui\craftcore\events\BackupRestoreEvent) — fired during a restore with the parsedentitiesarray,dryRunflag, andconflictPolicy. A listening plugin is responsible for writing the actual data and reporting asummaryback on the event.yui/craft-pluginlistens on this to restore yStore's own tables.BackupService::EVENT_COLLECT_SETTINGS(\yui\craftcore\events\CollectSettingsEvent) — fired while building thesettingsdomain during backup creation, so any plugin can contribute its own settings to the payload.
Extending with a new domain
Ship a backups.xml file in your own Composer package (any location Composer installs it to under vendor/), following the format used by src/etc/backups.xml in this plugin:
<backups>
<domain code="my-plugin">
<table name="{{%my_plugin_table}}" key="items" orderBy="id ASC" />
<settings source="plugin" />
</domain>
</backups>
yui/craft-backup discovers every backups.xml under vendor/ at backup time — no registration call needed. Then implement a listener on EVENT_RESTORE_ENTITIES (and EVENT_COLLECT_SETTINGS, if you registered a settings node) to actually read/write your plugin's data during restore.
Routes
Control panel (yui-backup/*): yui-backup/dashboard, yui-backup/settings, yui-backup/backups (alias for the dashboard), yui-backup/backups/download/<id>, yui-backup/backups/restore-log/<id>.
Controller actions (yui-backup/backup/*, POST unless noted): create, download/<id> (GET), restore/<id>, prune, prune-history, delete/<id>, manual-restore.
Console: yui-backup/backups/create (default action of yui-backup/backups).