Skip to content

code-lodge/stashify

Repository files navigation

stashify

Automated backup of an entire Shopify store with full media download and selective restore. Runs as n8n workflows with two independent backup strategies:

  • Local backup — store data + media to local/NAS storage
  • Google Drive backup — store data + media directly to Google Drive

Import one or both depending on your needs.

Prerequisites

  • n8n (self-hosted) with Docker CLI available in the container
  • anvil — the recommended base image (includes Docker CLI + rclone)
  • Shopify Custom App with Admin API access
  • rclone (Google Drive workflow only — included in the base image above)
  • Google Drive OAuth2 credentials in n8n (Google Drive workflow only)

What Gets Backed Up

Data (JSON)

Resource Backed Up Restorable Notes
Shop info Read-only reference
Policies Managed in admin
Shipping zones Reference only
Countries/taxes Reference only
Products With variants and images
Product metafields Per-product
Variant metafields Per-variant
Inventory levels Per-location quantities
Inventory items SKU/tracking info
Custom collections
Smart collections Including rules
Collection metafields
Collects Product↔Collection maps
Customers ⚠️ GDPR — passwords not restorable
Customer metafields
Orders Historical reference
Draft orders Complex state
Pages
Page metafields
Blogs
Articles Per-blog
Themes + assets Liquid, CSS, JS, images
Redirects URL redirects
Script tags
Price rules + discounts
Gift cards Security restrictions
Metafield definitions All owner types (GraphQL)
Metaobject definitions Schema + fields (GraphQL)
Metaobjects All types, upsert (GraphQL)
Shop metafields Shop-level custom data (GraphQL)

Media (files)

All binary files from Shopify's CDN, stored in a structured folder:

media/
├── products/
│   ├── classic-blue-t-shirt/
│   │   ├── 1_front.jpg
│   │   └── 2_back.jpg
│   └── canvas-tote-bag/
│       └── 1_product-photo.png
├── collections/
│   ├── clothing.jpg
│   └── accessories.jpg
├── files/
│   ├── images/
│   ├── documents/
│   └── videos/
└── manifest.json

Media sync is incremental — only new or changed files are downloaded.

Setup

1. Create Shopify Custom App

Shopify admin → SettingsApps and sales channelsDevelop appsCreate an app

Required Admin API scopes:

read_products          write_products
read_customers         write_customers
read_orders
read_inventory         write_inventory
read_content           write_content
read_themes            write_themes
read_files
read_script_tags       write_script_tags
read_shipping          read_locations
read_price_rules       write_price_rules
read_discounts         write_discounts
read_gift_cards
read_metaobject_definitions    write_metaobject_definitions
read_metaobject_entries        write_metaobject_entries

Install the app and copy the Admin API access token.

2. Copy Scripts Into the Container

Copy the backup scripts into your n8n container:

docker cp shopify-backup.mjs n8n:/opt/shopify-backup/shopify-backup.mjs
docker cp shopify-media-sync.mjs n8n:/opt/shopify-backup/shopify-media-sync.mjs
docker cp shopify-restore.mjs n8n:/opt/shopify-backup/shopify-restore.mjs
docker exec n8n chmod +x /opt/shopify-backup/*.mjs

To make scripts survive container rebuilds, create a persistent copy:

# Scripts on CasaOS host (persists across updates)
mkdir -p /DATA/Data/shopify-backup
cp shopify-backup.mjs shopify-media-sync.mjs shopify-restore.mjs /DATA/Data/shopify-backup/

Then set these n8n environment variables:

SHOPIFY_BACKUP_SCRIPT_PATH=/home/node/data/shopify-backup/shopify-backup.mjs
SHOPIFY_MEDIA_SCRIPT_PATH=/home/node/data/shopify-backup/shopify-media-sync.mjs
SHOPIFY_RESTORE_SCRIPT_PATH=/home/node/data/shopify-backup/shopify-restore.mjs

3. Set Environment Variables

Add these to your n8n instance (CasaOS app settings or container environment):

SHOPIFY_STORE=your-store.myshopify.com
SHOPIFY_ACCESS_TOKEN=shpat_your_access_token_here
SHOPIFY_API_VERSION=2025-01

Local workflow only:

BACKUP_DATA_DIR=/backups/data
BACKUP_MEDIA_DIR=/backups/media

Google Drive workflow only:

GDRIVE_BACKUP_FOLDER_ID=your_google_drive_folder_id
GDRIVE_MEDIA_STAGING=/home/node/data/gdrive-media-cache
RCLONE_REMOTE=gdrive
RCLONE_MEDIA_PATH=Shopify Backups/media
RCLONE_CONFIG=/home/node/data/rclone/rclone.conf

4. Import Workflows

In n8n: WorkflowsImport from File → select the JSON.

Workflow Purpose Schedule
n8n-backup-local.json Backup to local/NAS storage Daily 2:00AM
n8n-backup-gdrive.json Backup directly to Google Drive Daily 3:00AM
n8n-restore.json Restore from local or Drive Manual

Import one or both backup workflows. The restore workflow supports both sources.

Activate the backup workflow(s) and run manually once to test.

Quick Test (no n8n required)

Verify the scripts work against your store before importing to n8n:

export SHOPIFY_STORE=your-store.myshopify.com
export SHOPIFY_ACCESS_TOKEN=shpat_xxx
export BACKUP_OUTPUT_DIR=/tmp/shopify-test

# Run data backup
node shopify-backup.mjs

# Run media sync
export MEDIA_OUTPUT_DIR=/tmp/shopify-media-test
node shopify-media-sync.mjs

# Dry-run restore
node shopify-restore.mjs --file /tmp/shopify-test/shopify-backup_*.json --dry-run

Restoring

Open the Shopify Restore from Backup workflow and edit the Restore Configuration node:

const config = {
  source: 'local',                              // or 'gdrive'
  backup_path: '/backups/data/FILENAME.json',    // local path
  backup_file_id: '',                            // Google Drive file ID
  resources: 'all',                              // or comma-separated list
  dry_run: true,                                 // preview first!
  skip_existing: false
};

Always dry-run first, review the output, then set dry_run: false.

Selective Restore

{ resources: 'inventory', dry_run: false }
{ resources: 'products,product_metafields,variant_metafields,inventory', dry_run: false }
{ resources: 'pages,page_metafields,blogs,articles', dry_run: false }
{ resources: 'metafield_definitions,metaobject_definitions,metaobjects', dry_run: false }
{ resources: 'theme_assets', dry_run: false }

Notifications

Both backup workflows have a Notify on Failure placeholder node. Connect your preferred service: Email/SMTP, Slack, Telegram, or webhook (Uptime Kuma, Healthchecks.io, etc.).

Estimated Runtime

Store Size Products Data Backup Media (first run) Media (incremental)
Small <100 3-5 min 5-10 min <1 min
Medium 100-500 5-15 min 15-30 min 1-3 min
Large 500-2000 15-45 min 30-90 min 2-10 min

GDPR / AVG

The backup contains personal data (customers, orders). Under GDPR/AVG:

  • Restrict access to backup storage to authorized personnel only
  • JSON backups auto-expire after 30 days (retention cleanup in local workflow)
  • Media files don't contain PII (images only)
  • Google Drive: use a dedicated Workspace account with proper access controls
  • Right to erasure: document that backups rotate on a 30-day cycle
  • Consider encrypting the backup directory (LUKS, ZFS encryption, etc.)

Files

.
├── README.md                 # This file
├── LICENSE                   # GPL-3.0-or-later
├── shopify-backup.mjs        # Data backup script (REST + GraphQL)
├── shopify-media-sync.mjs    # Incremental media download
├── shopify-restore.mjs       # Selective restore with dry-run
├── n8n-backup-local.json     # n8n workflow: local/NAS backup
├── n8n-backup-gdrive.json    # n8n workflow: Google Drive backup
└── n8n-restore.json          # n8n workflow: restore from local or Drive

License

GNU General Public License v3.0 or later

About

Automated Shopify store backup and restore workflows for n8n

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors