Backups and restore
Every change to an environment's records is kept for the plan's days, so its records, or one model's, can be put back as they were at any moment since: after a bad migration script, a buggy action or a mistaken bulk edit.
What is kept
Each environment, development and production, keeps what every record was before each create, update and delete, whatever made it: the API, an action, the dashboard, a Shopify sync or webhook, a background job. Vector fields' embeddings are kept the same way.
| Free | Pro | Scale | |
|---|---|---|---|
| Restore records back | 1 day | 7 days | 30 days |
History starts when the environment is created, so a new environment fills up to the plan's days. Older history is deleted every hour; after a downgrade the shorter window applies at once. Only records are kept: files have their own versions and production rolls back to an earlier deploy.
Restoring
On the app's Settings → Backups in the environment to restore, pick a time (UTC) and every model or one, then Preview. The preview counts, per model, what the restore would do:
| What happens | |
|---|---|
| Put back | Records changed since then get the values they had then. |
| Made again | Records deleted since then come back with the same id, values and creation time. |
| Removed | Records created since then are deleted. |
Then Restore. It happens in one transaction. The app's writes made meanwhile wait for it. Only owners and admins can restore. Each restore is logged in Logs (an app event named restore) and in the team's audit log.
A restore doesn't run actions, and nothing tells Shopify: records synced from a store are put back as they were, and the next webhook or hourly reconcile brings them up to date again. Restoring one model leaves records in other models that point at it as they are.
Undoing a restore
A restore's own changes are kept like any others. Undo next to a past restore puts the records back as they were just before it. That also undoes changes made after the restore.
Copying production into development
To debug with real data, a development environment's Settings → Backups has Copy from production: every model, or one, with the fields to anonymize. Preview counts, per model, the production records copied in and the development records they replace; then Copy. Production isn't changed.
| What happens | |
|---|---|
| Ids | Each copy gets its own id. A belongs-to field points at its record's copy; copying one model, a link to a record it didn't copy is empty. |
| Vectors and files | Vectors are copied with their records. Files are copied into the development environment's own storage, so deleting them in one environment never touches the other. |
| Anonymized fields | Text gets a stand-in, the same value always the same one in a copy, so matches still match; email fields an address at example.com. Json is emptied, passwords and encrypted strings are left out, and a vector embedded from an anonymized field isn't copied. Fields that look personal (emails, names, phones, addresses) are checked to start with. |
A copy takes up to 50,000 records and 2,000 files; past that, copy a model at a time. Only owners and admins can copy. Each copy is logged in the development environment's Logs (an app event named copy) and in the team's audit log. It's kept in history like any write, so Undo next to it puts development's own records back.
Copies of a store's or customer's data follow production's Shopify redactions: when production gets shop/redact or customers/redact, the same records are deleted from the app's development environments, except one installed on that store itself.
Erased data
When Shopify sends shop/redact, history of that store's records, and of any record holding the store's domain, is deleted with them. For customers/redact, history of the customer's synced records and of any record whose old values hold the customer's id or email is deleted too, including what the app's own action changed to erase them. A restore never brings back data Shopify asked us to erase, and copies in development go too (above).
Storage
History counts toward production's storage, as Record history on the Usage page. Its size follows how often records change: an app that rewrites many records every hour keeps more history than one that mostly reads.