Case study · Web development

Caffeine Interactive

WordPress to Static Astro Migration for Our Own Site

We rebuilt our own site as a static Astro site and moved it to our own server in five days, keeping the design and every URL. Two checks on every deploy make sure no page or title is lost by accident.

Overview

Caffeine Interactive is our own company, and caffeineinteractive.com is the first place most prospects see our work. For years it ran on WordPress with Elementor, hosted on WP Engine.

In late summer 2026 we rebuilt it as a static site with Astro and moved it to our own server, where Caddy serves it. We started on August 27 and moved DNS on September 1. The design stayed and the URLs stayed. What changed is what the server does when someone visits.

Caffeine Interactive: Overview
Caffeine Interactive: Overview, mobile view

The Challenge

The old site carried the costs every WordPress site carries. Plugins needed patching, and every plugin was a way in for someone who found a hole in it before we did. A page builder adds markup nobody asked for, so pages kept getting heavier. We tell clients that performance and security matter, and our own site was not the best argument for that.

The harder part was the move itself. Most site migrations lose search traffic: pages get renamed, redirects get missed, meta descriptions quietly change, and rankings drop a few weeks later when nobody is watching. We had to change the foundation without losing a single page along the way.

Same design, different foundation. The site is built once and served as files. Two gates run on every deploy, so a build that drops an old URL or quietly changes a page's title or description never ships.

What We Built

A static site with nothing to attack

The old site ran PHP and queried a database on every request. The new one is built once, in advance, and visitors get finished HTML. There is no database, no login page and no plugin layer. The build uses four packages, and none of them run on the server.

The same design, measured rather than copied

Colors, typefaces, type scale, spacing and breakpoints came out of the old site's compiled CSS, not from screenshots. We rebuilt the markup underneath clean instead of reproducing Elementor's nested wrappers and one-off values. We also learned that the rendered page is the specification: on Elementor pages, hero images and dividers are CSS backgrounds, so a text export drops most of what a page looks like. We threw away two early rebuilds built from an export before we caught it.

Two gates on every deploy

We made "don't lose rankings" something the build enforces. The first gate fails the deploy if any URL from the old site lacks a recorded decision (kept, 301 redirected to a named page, or retired with a 410), or if a redirect points somewhere that does not exist. The second fails it if any page's title or meta description changed without a written, approved reason.

That process caught problems in the original. Six pages had meta descriptions copied from unrelated pages, and two titles had typos that had been live for years. Copying the old site exactly would have copied those too.

Fixed, not reproduced

The old site used one heading size for every screen, so a 52px headline landed on a 375px phone. Form field borders did not meet contrast requirements. Blog cards announced the same post to a screen reader three times. We fixed all of it without changing how the site looks. We also expanded the structured data from two types to nine, so search engines and AI tools can tell a service page from a case study, an article, a set of FAQs or a person.

Tracking we can review

We removed Google Tag Manager, which lets anyone with access add scripts to every page without touching the code. The tracking we actually use now lives in the codebase, where it is reviewed like anything else, and three unused trackers are gone. Forms run through our own n8n instance instead of a WordPress plugin.

Easy to change

Blog posts are Markdown files in git, and category and tag pages build themselves from each post's frontmatter. A deploy is one command that builds, runs both gates, copies the files and reloads Caddy. We kept the WP Engine site running after cutover, so rolling back would have been a DNS change rather than a rebuild. Since cutover, the same pipeline has carried a content overhaul: 56 old blog posts pruned, each redirected to a related page, and new case studies like this one.

Built with an AI coding agent

We did the build with Claude Code, Anthropic's AI coding agent, working from a written brief of the rules: keep every URL, keep every title and description unless we decide otherwise, add no dependency without asking, and check every page against screenshots of the old site. The agent wrote the code and ran the checks. We reviewed each change and made the calls. We use the same approach on client work, such as the Kan-Haul LoadTracker PHP upgrade.

Caffeine Interactive: What We Built

Results

  • Requests per page down from 101 to 121 to 21 to 33.
  • Homepage size down from 1,957 KB to 699 KB, and the portfolio page from 4,612 KB to 815 KB.
  • Interior pages load in 90 to 214 ms, down from 247 to 831 ms.
  • Median PageSpeed mobile score up from 48 to the low to mid 80s across two benchmark runs.
  • Lighthouse SEO 92 to 100, Best Practices 77 to 100, Accessibility 100.
  • About 4 KB of JavaScript across the whole site.
  • Every old URL has a recorded decision, and no page was lost by accident.