Creating a Low Carbon Umbraco Website

Using Umbraco Delivery API, NextJS's Static Site Generation, and uSync, to create an ultra-low CO2 Umbraco website

Aiming to provide data APIs to measure sustainability, Etive Mòr launched in late 2023. For the first few months, our website was a hastily-customised installation of Umbraco. We decided to make something a little more permanent to deliver our new products through. Given our extensive experience with Umbraco (and the fact we were already using Paul Seal’s Clean starter-kit for the placeholder site), the CMS felt like an obvious choice.  

 

Around the time we were making the decision to rebuild, we received an email from Umbraco saying that they’re running a Sustainability Challenge for their 19th birthday. That solidified our choice to go with Umbraco, and we set an ambitious aim to cut our website's CO2e emissions in half. 

 

Using the latest Umbraco, Github & NextJS features, we took a holistic approach to reducing our CO2e emissions. We reduced our scope 1 emissions by 75%, focusing mostly on the page weight. We reduced our scope 2 emissions by shutting down our production server for 90% of the day. And we reduced our scope 3 emissions by cutting our demand for Github’s action runners by more than 80%.

 

Improvement metrics

Our journey is described in detail below, but some highlights are:

  • The home page is 188.6kb, down from around 800kb
  • This website produces 0.03-0.06g CO2e on the first page view (according to WebsiteCarbon.com & Ecograder), down from 0.24-0.25g
  • As an added bonus, the website costs less than £2 per day in hosting fees
  • The application’s architecture redesign reduced our Umbraco server energy consumption by more than 90%
  • The application’s devops redesign reduced our compute-time in Github’s servers from 25hours/month to 200 3.5hours/month
  • The site scores better than 80% of URLs considered by Ecograder, giving it an A+ grade: https://ecograder.com/report/N9P2iHh4dz8Rmmg9mKH05oRM
  • The site scores better than 96% of urls considered by Website Carbon Calculator: https://www.websitecarbon.com/website/etive-mor-com/

The new Content Delivery API and Headless Umbraco backoffice

The best way to reduce CO2e emissions is not to produce them in the first place, and Umbraco's new APIs have allowed us to stop doing just that. Umbraco released the Content Delivery API in version 12, with additional features in version 13. It brings native headless capabilities to Umbraco with the promise of future development from HQ. Previously if you wanted to create really great headless applications with Umbraco, the first order of development was a time-consuming build phase to produce a bespoke API. 

NextJS and Static Site Generation

Adopting the new Content Delivery API allows us to use Static Site Generation (SSG). This development approach, outlined in detail below, pre-builds all of our front-end pages. Once the pages are built, they're deployed to a serverless webapp in Azure, behind a Content Delivery Network (CDN), rather than through an energy-intensive web server.  

 

In a traditional Umbraco site, the Umbraco application is responsible for accepting requests from end-users, building the HTML page, and delivering that entire page on the fly. To achieve this with good uptime, usually you need to have a substantial server sitting waiting for requests.

 

An SSG generated website operates differently. The front-end’s pages are all created at build-time. When an end-user makes a request to the website, it’s served immediately from the CDN, skipping Umbraco entirely. This means we’re able to turn off our Umbraco server for the majority of the day. Most pages on the site are created one time, irrespective of the number of pages who will view them. 

 

The front-end is configured with Incremental Static Regeneration, so it periodically reaches out to the Umbraco backoffice to update stale content. When a user lands on a “stale” page , they’re immediately served that stale content. In the background, the NextJS app reaches out to Umbraco, collects any content changes, and rebuilds the page before the next user comes along. If that process fails for any reason, users are just served the stale static content until the Umbraco site can respond. Again, irrespective of how many users view a page, it's only ever built one time. 

 

95% reduction in Umbraco backoffice uptime & associated CO2e

In practice, SSG means that our costly production Umbraco server spends more than 23 hours of the day turned off, and most of the rest of the time it runs on a low-energy appservice plan. Through this, we achieve a 95% reduction in CO2e from our Umbraco backoffice application's scope 2 emissions.

 

This has some additional benefits to the business. Downtime risk is significantly reduced - even if there's a fatal error in the Umbraco application, the front-end of the website stays up and running. Cost reductions are an additional benefit - a comparable always-on instance would set us back over £200/month, while our projected Azure spend on the website this month is below £40.

Low Carbon Architecture

Our application architecture is designed from the ground-up to be low-carbon. We’ve configured the website so that it can be completely deleted from Azure, and spun up again within five minutes. This isn’t just a benefit of being a tiny site. The front-end only shows a few pages, but the Umbraco backoffice provides content for a data API, hosting thousands of nodes. 

 

The SSG generated front-end is just plain old HTML templates, a small CSS file, a fairly large javascript file, and some JSON data, so we serve it entirely through Azure’s Static Site CDN. Users are served a tiny amount of data from a CDN endpoint physically near to their device. We serve all of the site’s media through Azure’s CDN too. 

App Architecture

App Architecture (click to open)

The Umbraco application runs on Azure’s scalable web-apps. Thanks to our use of SSG, we don’t need our Umbraco servers to be high-performance, as it only serves the front-end during the build phase, and periodically for incremental regeneration. We currently have it running in the lowest paid tier, on a shared instance. Now and again we need to do a large content import. For those tasks, we scale the server up to a high-performance tier, then scale it back down.

 

For a long time, we didn't run a database server for the Umbraco site. We opted instead for a filesystem SQLite database. In a typical production Umbraco site, the approach is a little risky, as Azure can re-provision the production server automatically, deleting the SQLite database and all of its content, requiring a lengthy cold-start from Umbraco. Under SSG this approach was fine, since the Umbraco site never needs to respond immediately to end-user requests.  

 

We mitigated the risks of our SQLite database disappearing by having the application configured with Umbraco’s unattended installation, combined with uSync’s import-on-startup feature. When the server starts for the first time, Umbraco installs itself, and then uSync imports all missing content. This process would take at least a few minutes, which is fine when we’re just pulling Umbraco content when running builds. We'd recommend trialling this approach to anyone looking to implement SSG for small and infrequently changed websites. 

 

With thousands of nodes in the back-office, we've reached the limits of our filesystem database approach (the cold-start times are now several minutes, which increases our build-time pretty significantly). We’re now moving to a Serverless Azure SQL instance. Still, we avoided around 4 months of CO2e emissions from a dedicated SQL instance.

 

Because we can delete our servers and start from naught in a couple of minutes, we don’t maintain long-lived staging or dev servers. When we have a new feature to release, we create a staging server from scratch, we then delete the server once we've done our QA/UAT work on it. We also deprovision all non-production servers over the weekend. 

Low Carbon Devops

The application’s devops pipeline is designed to be as close to zero-carbon as possible. We have three strategies for this: 

  • Physically locate our build servers in Scotland, where the majority of energy is renewable or low-carbon
  • When we can’t locate our build servers in Scotland, try to make them run in a datacenter with a low carbon energy mix, ideally at the least carbon-intense time of day possible
  • Create demand for as few servers as possible to reduce embodied emissions

As we’re writing, Scotland’s energy mix is 76% renewable, 21% low-carbon, and less than 2% from fossil fuels. Annually, renewables produce more than 100% of Scotland’s gross energy requirements (though we do still use a lot of hydrocarbon-based energy when the wind isn’t blowing).  Due to our relatively low-carbon local energy mix, running as much of our computation in Scotland is important to us. To locate our devops pipelines in Scotland, we have self-hosted Github Action runners in our Edinburgh office. 

Scotland's energy mix

Scotland's energy mix (click to open)

The majority of our devops pipeline executions occur during office hours - because that’s when we’re working on the application. During office-hours, we'll probably have or workstations turned on - because that’s how we’re working on the application - and we're rarely using 100% of the memory/processing power of these devices.

 

For those reasons, the devops runners are installed on the same workstations we build the software on. In exchange for a small amount of RAM and CPU cycles on our own desktops, we guarantee the actions run in a low-carbon environment during office hours. 

 

Some of our pipelines run in the evening though. If we commit right at the end of the day, we’d kick-off a build, which wouldn't have an in-office workstation to run on. For those, we automatically fall-back to Github’s cloud-hosted runners. They’re a bit more tricky to understand from a CO2e point of view, as we can’t currently tell Github that we have a preference for renewable energy, and they don't reliably tell us how much energy was consumed by an action. To mitigate this source of carbon, we use Jord, an action that defers builds depending on the carbon intensity of github’s datacenter. This is based on data from the Green Software Foundation’s Carbon Aware API.

Movable github action runners

Movable github action runners (click to open)

It’s important for us to reduce our demand to external providers as much as possible. A lot of CO2e in the computing industry comes from embodied carbon. That is, carbon from the manufacturing and disposal of servers - even if they’re sitting entirely idle, our servers have a significant CO2e impact. The fewer of Github’s servers that we demand, the fewer Github brings into existence. 

 

Averaged across the last three months, we’ve used around 1,200 minutes/month (25hrs/month) of Github’s server time. Last month, we moved them onto locally hosted machines, and now use around 200 minutes per month of Github’s server time, doing the remaining 900 minutes on machines which already existed, and are already turned on. This reduces our embodied emissions in our devops pipeline to ¼ of its previous level. 

 

Note that the “chasing the sun” approach to finding the best energy mix may be counterproductive, and isn’t a one-size-fits-all solution, Adrian Cockroft of Amazon’s sustainability team summarises the reasons for this best.

Low Carbon Style & Design

Our site isn't the most extravagant design. It's simple, grey and white, with a little bit of colour here and there. You'll notice as you're browsing around that, except for the blog pages, we don't have many images. The images we do have are mostly low-bandwidth cacheable SVGs. Keeping the design very simple has allowed us to rapidly develop the front-end, while keeping style related assets as small as possible. 

 

We use one custom font, Inter. It's a beautiful open-source font, which works on all devices. Keeping our minimal design consistent across browsers is important. It's 47kb, and it's cached so that users only ever download it one time. 

 

We use TailwindCss for our stylesheets. It’s a maximally reduced & compressed style framework, which parses through all of the front-end files, and throws away unused code before publishing. We only send style rules to the end-user if they’re actually used. The result is an 8kb stylesheet, a 4x improvement over our 35kb bootstrap stylesheet. The sheet is cached and only delivered once per user.

Into the future

 

Following the prompt from Umbraco, we’ve taken steps to architect, design, and develop our website in a way that will produce as little carbon as possible into the future. We initially set a carbon reduction target of 50%, and we’ve considerably overachieved in that regard . We still have a lot of steps to take to keep our software related CO2e emissions as low as possible. We’ve identified a number of cost-savings alongside our CO2e savings, which provide additional incentive for us to keep energy consumption as low as possible. 

 

We were in a fortunate position for the Umbraco Sustainability Challenge, as we were looking at a greenfield Umbraco project at the exact time it came along. Not all Umbraco projects will be in the same position, but we hope that, by publishing our architecture & development decisions, we encourage others to look into the Content Delivery API + SSG approach to Umbraco development in their upcoming projects.

image of Liam Laverty

Liam Laverty

Posted 19 February 2024