A read-only backup tool that exports your entire Shopify store to local JSON files and downloads all product images. Designed to run on a schedule so your store data is always recoverable — even if Shopify has an outage or data is accidentally deleted.
The tool is completely read-only and will never modify your store. It only uses GET requests against the Shopify Admin API.
| Resource | File | Includes |
|---|---|---|
| Products | products.json |
All fields, variants, product metafields, variant metafields |
| Product images | images/{product_id}/ |
Actual image files downloaded to disk |
| Customers | customers.json |
All fields, customer metafields |
| Orders | orders.json |
Full order history (all statuses), order metafields |
| Pages | pages.json |
All published pages |
| Collections | collections.json |
Smart + custom collections with metafields |
| Blogs | blogs.json |
All blogs with their articles |
| Shop metafields | metafields.json |
Store-level metafields |
Each run also writes a status.json with timestamps, per-module success/failure status, item counts, and any errors.
/backups/shopify/
├── 2026-01-27/
│ ├── products.json
│ ├── customers.json
│ ├── orders.json
│ ├── pages.json
│ ├── collections.json
│ ├── blogs.json
│ ├── metafields.json
│ ├── status.json
│ └── images/
│ └── 8293748/
│ ├── 1.jpg
│ └── 2.png
├── 2026-01-26/
│ └── ...
Old backup directories are automatically cleaned up based on the retention policy.
All configuration is via environment variables. Copy .env.example to .env to get started.
| Variable | Required | Default | Description |
|---|---|---|---|
SHOPIFY_STORE |
Yes | — | Your store domain (e.g. my-store.myshopify.com) |
SHOPIFY_ACCESS_TOKEN |
Yes | — | Admin API access token (starts with shpat_) |
BACKUP_DIR |
No | /backups/shopify |
Where backup directories are written |
RETENTION_DAYS |
No | 30 |
How many days of backups to keep |
- In Shopify admin, go to Settings > Apps and sales channels > Develop apps
- Create a new app
- Under Configuration, add Admin API scopes:
read_productsread_customersread_ordersread_contentread_metaobjects
- Install the app and copy the Admin API access token
The image uses a multi-stage build on node:20-alpine and runs as a non-root user.
docker build -t shopify-backup .
docker run \
-e SHOPIFY_STORE=my-store.myshopify.com \
-e SHOPIFY_ACCESS_TOKEN=shpat_xxxxx \
-v /path/to/backups:/backups/shopify \
shopify-backupOr with an env file:
docker run --env-file .env -v /path/to/backups:/backups/shopify shopify-backupThe container runs the backup once and exits. Schedule it with cron, Kubernetes CronJob, or your deployment platform's scheduler.
- Create a new Application in Dokploy pointing to this repository
- Set the four environment variables above in the Dokploy UI
- Add a persistent volume mounting your backup storage to
/backups/shopify - Under Advanced > Scheduled Tasks, add a cron job:
0 2 * * *(runs daily at 2 AM)
The backup output directory will be picked up by whatever sync pipeline you have on the host (e.g. B2/Backblaze, rclone, restic).
pnpm install
cp .env.example .env # fill in your values
pnpm dev # run backup with tsx| Command | Description |
|---|---|
pnpm dev |
Run backup locally (via tsx) |
pnpm build |
Compile TypeScript to dist/ |
pnpm start |
Run compiled output |
pnpm test |
Run test suite (Vitest) |
pnpm test:watch |
Run tests in watch mode |
pnpm test:coverage |
Run tests with coverage report |
pnpm lint |
Lint with ESLint |
pnpm typecheck |
Type-check without emitting |
- Reads configuration from environment variables
- Connects to Shopify Admin API (pinned to API version
2025-01) - Fetches each resource type using cursor-based pagination
- Fetches metafields for products, variants, customers, orders, and collections
- Downloads all product images to disk (skips already-downloaded files)
- Writes JSON files to a date-stamped directory
- Writes
status.jsonsummarizing the run - Deletes backup directories older than the retention period
- Exits with code 1 if any module had errors
All API calls use exponential backoff with retry on 429 (rate limit), 500, 502, 503, and 504 responses, as well as network errors (ECONNRESET, ETIMEDOUT).