Project One Motors · 2023-2026

A supercar dealership with a website faster than its cars.

0.4spage load, from 4 seconds

The rebuilt Project One Motors site: a supercar listing on a dark background, loaded in under half a second.
The listing page. The car loads before you finish scrolling to it.

Role

  • web
  • seo
  • build

Stack

  • Next.js
  • Tailwind
  • Cloudflare
The problem
A WordPress build that took four seconds to load a photo, and needed touching in three places to add a car.
What I built
A custom Next.js platform on Cloudflare's edge, plus an admin where publishing a car is one workflow instead of three.
The result
It loads in four tenths of a second.

The apology is the part I remember. Someone pulled their own website up on my phone to show me a car, and then said sorry for it while a grey box sat there thinking about the photograph. They knew. They'd quietly stopped sending people the link.

Listing page - images first, then the specs.

The build underneath was WordPress on shared hosting with a page builder on top and the usual pile of plugins, each one quietly charging rent. Every visit meant PHP booting, a run of database queries, HTML assembled on the spot, then a theme loading its own scripts and styles for features nobody used - all from one server a long way from a person sitting in Al Quoz traffic.

But the real weight was the photographs. A dealership site is a photo gallery with prices on it, and these were going out as full-resolution JPEGs straight off the camera, four and five megabytes each, at dimensions no phone would ever draw. So the four seconds wasn't one slow thing. It was the server thinking, then the page bloating, then several megabytes of cars crawling down a mobile connection.

A dealership's organic search traffic is its foot traffic. The migration was the risky part, and it held.

The cost nobody could see was worse. Publishing one car meant touching it in about three places - the listing, the gallery, a block on the homepage - each edited separately, each easy to get half right. So cars sold and stayed listed, or went up with the correct price in one spot and last month's in another. A slow site you can wait out. A publishing flow people dread just rots.

Moving 491 cars without losing one

The rebuild is Next.js on Cloudflare's edge, which mostly means pages stop being assembled on demand and start arriving already finished, from a machine minutes away from whoever asked. Cars live in a database at the edge, photographs live in object storage next to it.

The migration itself was 491 cars and 4,820 photographs. The cars went across with their original publish dates intact, because a listing that suddenly claims to be new is a listing a search engine has to learn from scratch. Every photograph was converted to WebP on the way in, with anything already WebP passed through untouched rather than re-encoded. All 4,820 landed. Zero failures is the only acceptable number when the failure mode is a car with no pictures.

The data turned out to be in worse shape than the site. Eleven cars in the entire export had a transmission recorded. Every single car's fuel type said the same thing, including the electric ones, because the old form had one default and nobody had ever changed it. So the migration carried an AI pass: Claude wrote a description for all 491 and filled the missing technical fields on 488, grounded against a make, model and trim catalogue rather than left to remember. Three came back garbled and got fixed by hand. I'd rather write that down than pretend a batch job across nearly five hundred records ran clean.

The part where a rebuild quietly wrecks a business

Move a site, change the addresses, and Google treats every page as brand new. Rankings reset. Months of accumulated position evaporate, and a faster site nobody can find is not an upgrade.

So every car kept its address, and where the shape had to change, the old one redirects to the new one permanently rather than dying. The category URLs the old build had invented all land on the inventory page instead of a dead end. The structured data came across too, so listings kept whatever rich results they'd already earned.

That redirect list grew after launch, which is the part I'd tell anyone doing this. Weeks in, Search Console was still reporting impressions for old listing URLs that were returning 404s. They weren't in the original map because nothing on the site linked to them any more - only Google remembered. They got redirects. A migration isn't finished on cutover day. It's finished when Search Console stops finding things you forgot.

The admin is deliberately boring

The public side is what you'd expect: fast, clean, built around what someone actually looks at when they're considering a car this expensive - the images first, then the specifications, then a way to ask about it without filling in a form.

What buyers see. Fast, and always in sync with the showroom.

The part nobody sees is the part that mattered. I built the team a custom admin where publishing a car is one workflow instead of three. Images, specifications, availability, status - one place. The listing either exists or it doesn't. It can't half-exist across three systems any more.

Everything in it is shaped around what actually goes wrong on a showroom floor rather than what looks tidy in a form. Photos drag into order and any one of them can be made the cover, because the best shot is rarely the first one off the card. Rows select in bulk, so marking a run of cars sold is one action. The electric cars hide the engine fields and show battery and range instead, because a spec table that demands a cylinder count on an EV teaches people to type anything to get past it. And the same generator that backfilled the migration sits in the form as a button, so a new car arrives with its specs and its copy already drafted and a human editing rather than starting at a blank field.

Then I went back through it with Lighthouse open, because a fast framework doesn't make a fast page on its own. Images are now transformed at the edge to whatever size the layout genuinely asked for: the homepage hero went from 978 KB to around 80, and cards that had been shipping 130 to 250 KB each went to between 9 and 20. Same photographs, same grade, a fraction of the bytes.

The admin. Deliberately boring. Boring is the feature.

An external security test later found exactly one thing wrong with the whole thing: the admin login had no rate limiting. It's now behind a challenge that's verified server-side before the password is even looked at. Unglamorous, and that's the job.

The dealership sends the link now. And when a car sells, someone marks it sold once, on the spot, from wherever they're standing - which is the only version of that job anybody was ever going to actually do.

Two ways on from here: the next case study - The WhatsApp bot that replaced the photo index, or the films.