
Nova Scotia Trail Running Rebuild
Jun 3, 2026So long ago I don't actually remember when, I spun up a quick WordPress site using some basic styles and ACF in a similar style to how we built sites at work. Having absolutely zero design eye, I matched some colours to the logo and gave it some simple layouts and away it went. It was primitive but functional, got across the information it needed to.
Since then, Jodi has added a ton of races, including Capes 100 and many more, along with offering coaching and group runs. It felt like the current site wasn't doing any of that justice.
What I built
Building a site is easy; I've been doing that for more than 20 years. Coming up with something that looked good and was easy on the hosting budget while not being open to the usual WordPress vulnerabilities is the fun part.
WordPress does the trick and is easy to use, but hosting it is less than pleasant. My goals for this were relatively straightforward:
- The site needs to look a whole lot better
- We need a CMS, but it shouldn't be WordPress
- The site should be statically generated
Static sites offer many benefits, but for this site specifically I cared about speed and cost. The CMS was largely irrelevant, but Node-based with low overhead was preferable. The stack I ended up with was Payload CMS and Astro, hosted on fly.io and Cloudflare.
Payload CMS
I'd been researching Node CMS products for my main job, and Payload was the one that I enjoyed the most while testing and prototyping. No better way to get familiar with a product than to use it in an actual project!

The setup is fairly simple: A few collections for the content types (pages, races, media, etc) and an editing experience that is reminiscent of ACF in WordPress.
Astro
The choice for the frontend framework was purely for my learning and... well, fun. I've wanted to try it for a long time, and this seemed like the perfect project to test it out on.
The blocks end up similar to how I used to build them in ACF. A single file with markup and logic and a defined type at the top so we can be certain of the shape of our content. Templates and different pieces (header, footer) are the same and end up being fairly low-code compared to certain frameworks.
At build time, Astro fetches the published content from Payload's REST API and prerenders every page to a flat static file. The same data layer feeds the dev server live while I'm working locally, then generates the static output for production. When Jodi publishes a change, a webhook kicks off a fresh build automatically.
Infrastructure
The most fun but least visible is the infrastructure and deployment, where the backend and frontend take separate paths. The Payload CMS deploys via GitHub Actions to Fly.io, where a single, small, on-demand machine hosts it against a remote Postgres database on Neon. The frontend is handled entirely by Cloudflare: it builds the Astro site straight from the Git repo and serves the prerendered files from the edge as static assets. No server to run, just files and edge caching. Media is processed in the CMS and uploaded to Cloudflare R2, so no virtual disk is required.
What's next
The site is now live in its initial release state, which mostly mimics and adds to what existed previously. I've turned it over to Jodi to update and edit the content and keep it up to date as the race season progresses. We're going to work on integrating race results and recaps into the platform, and eventually add more bespoke race pages like the Capes 100 page.