Skip to Content

Website Migration Toolkit

The Unglamorous Half of a Re-Platform: Images, Redirects and Indexing
25 September 2026 by

Client: International Salon Supplies

Role: Developer

Period: Jul 2023 – Jul 2025

Status: Completed (migration tooling)

Tech stack: Node.js, Jimp, Sharp, AWS SDK v3, DigitalOcean Spaces, CDN, axios, CSV, SQL

Scripts and tools behind two website migrations: normalising and converting ~21,000 product images, generating the database updates to match, moving ~17,500 files to a CDN, and crawling ~6,500 site URLs and ~5,400 product URLs across environments to build and verify the redirect map before and after launch.

Why this matters

A new storefront gets the attention, but migrations fail on the boring parts: broken images, dead links and lost search rankings. These tools were built to make sure the ISSWA 2.0 launch and the move to a new CMS didn't lose any of those.

1. Normalising ~21,000 product images (2023)

The legacy wholesale site had product images in mixed formats (JPEG, PNG, TIFF) and every aspect ratio imaginable. The conversion pipeline had four steps:

  1. Read an export of product IDs and image lists (several comma-separated URLs per row) and resolve each URL to its file path.
  2. Convert: scale each image to fit a 1000 × 1000 white canvas, centre it and write a web format alongside the original.
  3. Generate SQL: rewrite the file extensions and emit one UPDATE statement per product, so the database matched the new files.
  4. Clean up: remove the originals once the new files were verified.

A second variant produced compressed 800 × 800 output at reduced quality with a separate error log. The input exports held ~21,000 image rows.

2. Moving the archive to a CDN (2024)

For ISSWA 2.0, ~17,500 legacy CMS files (product images by product ID and manufacturer SKU, brand images and attachments) moved to DigitalOcean Spaces behind a CDN:

  • A recursive walker converts local paths into clean object keys (normalising separators and spaces), detects content types and uploads each file as public-read.
  • Uploads run sequentially with a small delay to stay within rate limits, and failures go to a timestamped log.
  • After upload, the sync engine's CDN module builds an image manifest for each product (header, gallery and variation images), so products picked up their images automatically.

The same predictable URL scheme later powered in-cell images in the brand price list generator.

3. Crawling the site before and after cut-over (2024)

A small URL checker takes a list of paths, requests each one against a configurable base URL (production, staging or a cache test server) and records the HTTP status.

  • Sequential by design, so it's gentle on production.
  • The same path list runs against every environment, so you can compare before and after.
  • Results doubled as the redirect-map worksheet (source, destination, status, done).

Across runs it checked ~6,500 site URLs and ~5,400 product URLs. That fed a redirect plan of ~7,155 mappings, which became permanent 308 redirects at the edge.

4. Checking what Google actually indexed (2025)

After launch I wanted to know which of the 5,503 product URLs in the sitemap were indexed. The first attempt ran a site: search per URL and parsed the result.

It's the wrong approach: scraping search results gets blocked quickly and isn't reliable. The right tools are Google Search Console's coverage reports and URL Inspection API. I shelved the script. It's included here because knowing when to drop an approach matters as much as building one.

Takeaways

  • Treat URLs as a dataset. Crawl them, diff them and track them in a worksheet before launch.
  • Generate the database changes from the same script that moves the files, so they can't drift apart.
  • Keep image URLs predictable. Other tools will come to depend on them.