Skip to main content
Version: 2.0.0

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.gz file, stored under storage/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:

  1. 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.
  2. 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:

DomainContents
settingsPlugin settings collected from every plugin that listens for the collect-settings event.
storesStores, currencies, countries, tax rates and tax category groups.
catalogProducts, product types, product data/variants/mappings, prices and price history, catalog rules.
customersCustomers, addresses, subscribers, blacklist, social accounts.
ordersOrders, order items, invoices, order history/statuses, quotes.
shippingShipping methods, fees, zones, rules, table rates, delivery time slots/holidays/exclusions/reservations.
paymentsPayment methods and payment transactions.
marketingCoupons, gift cards, wishlists, cart shares, watchdog, email templates, search terms.
automationFlows, flow runs, flow logs, scheduled actions, credentials, audit trails.
systemCore 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

  1. An admin clicks Create Backup on the Dashboard. The underlying BackupService::createBackup() accepts a $domains array 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).
  2. 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 to storage/yui/backups/backup-<timestamp>-<random>.json.gz. A BackupRecord row tracks the file, checksum, domains, record count, and size.
  3. To restore, the admin picks a stored backup (or uploads/pastes a manual payload) and chooses Dry Run or Restore, plus a conflict policy.
  4. The plugin validates the payload's schema version and checksum before touching anything. If validation fails, the restore is rejected with no changes made.
  5. 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 by yui/craft-backup itself — see Requirements.
  6. Every restore attempt (dry run or execute, stored or manual) is logged as a BackupRestoreRecord with 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-core version 1, for the underlying BackupService, 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. Without yui/craft-plugin active, yui-backup still installs and its CP pages still work, but a backup would only contain domains registered by whatever other packages ship a backups.xml, and a restore's EVENT_RESTORE_ENTITIES would 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 / :delete permission. 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 accepts 0, 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 .json or .gz extension; 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 parsed entities array, dryRun flag, and conflictPolicy. A listening plugin is responsible for writing the actual data and reporting a summary back on the event. yui/craft-plugin listens on this to restore yStore's own tables.
  • BackupService::EVENT_COLLECT_SETTINGS (\yui\craftcore\events\CollectSettingsEvent) — fired while building the settings domain 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).