The Green Web Dev Book

by Mikey Hogarth

Ideas and resources to help you build more environmentally sustainable web applications.

This book is a work in progress and is currently in an incomplete state.

Foreword

Meet Bob. A few years ago, Bob decided to start driving an electric car in an effort to reduce his reliance on fossil fuels. Despite now running his vehicle entirely from renewable energy, Bob still takes steps to conserve energy where possible.

  • He turns off the engine when his vehicle is stationary.
  • If only travelling a very short distance, he prefers walking over driving.
  • Should anyone else be travelling in the same direciotn, he will offer to give those people a lift.

Nobody thinks Bob is weird for behaving like this - in fact, these are the very same behaviors that Bob has always practiced, even before switching to an electric vehicle. If Bob were to leave his engine running while parked, or if he were to drive twenty seconds up the road to buy a newspaper, people might say that Bob was using his vehicle irresponsibly. If he didn't offer lifts to people traveling in the same direction... well then they might say even worse things about him.

Conserving fuel is something that car owners simply accept as being a good idea. Most people are aware of the high price of fuel and are familiar with the things that contribute towards fuel consumption. Fortunately, measuring and monitoring fuel consumption is very easy because the associated metrics are all highly visible - the dashboard of a vehicle displays its current fuel level in real-time and almost all petrol stations advertise their fuel prices clearly in large illuminated letters on their forecourts (particularly frugal drivers watch these prices very closely).

The penchant for saving energy is not purely limited to the realm of car ownership - we all get electricity bills and we all know that we should turn things off when we're not using them. Money may be the main driver for our energy-usage behaviors, but there is something more primal going on here; in the back of our minds, the very notion of waste feels awful to us. No matter how far we've emerged from the primordial soup, our desire to conserve resources is an instinct that runs deep within our ancient heritage. Modern humans simply hate seeing things go to waste - renewable or otherwise.

So why then do we seldom apply this same instinct when it comes to building digital applications? Perhaps it's because the impact is so much more difficult to measure or that the wastage is too abstract to comprehend - but in reality, the principle is exactly the same and all digital products have, in various capacities, an energy footprint. This book aims to take our natural inclination to save energy and apply it to the domain of building web applications. It aims to show you that by prioritising sustainability, you can both save money and build better software.

What is this book?

The core aim of this book is to highlight the relationship between web application development and climate change such that you can make it a factor in your technical decision-making.

The main bulk of the text presents ideas and examples to illustrate how we can contribute to reducing the energy cost of the applications we develop. It also explores some of the major themes that you might encounter when approaching this subject within your organisation or in your daily life, and aims to address some of the questions you may have about sustainable web development.

The intended audience for this book is anyone who is involved in the development of web applications - not only web developers but also peripheral roles such as content creators, delivery managers, product owners and scrum masters. It is not necessary to read this book in chapter order, neither is it necessary to read the book in its entirity if you are only interested in a particular aspect of development. The following list details the major themes that are covered.

  • General Tips applicable to all aspects of web development.

  • Styles and how they can be made more efficient.

  • Content and Markup - the information that your applications deliver to users and its structure.

  • Frontend code that runs on client machines - JavaScript or otherwise.

  • Backend code that runs on your own pysical servers or in the cloud.

  • Images - often the biggest offender in terms of a client's energy footprint and often where the lowest hanging fruit is in terms of optimising.

There is a lot more to running sustainable web applications than just these themes, however these are what we will focus on here - Appendix A provides references to some additional resources if you don't find what you're looking for in the above list.

What is this book not?

It is also worth quickly pointing out what this book is not.

  • This book assumes that you believe that climate change is real and makes no attempt to convince you of this fact. The climate crisis itself is only mentioned very briefly.
  • This book assumes you already have a working knowledge of web development (although a complete working knowledge is not required if you are only interested in particular aspects). I have, however, attempted to make the text as accessible to all audiences as possible.
  • This book is not an exhaustive list of everything you need to do to create sustainable web applications. Here we mainly focus on some of the major themes and present some examples to give you a flavour of the kinds of things you can do
  • This book does not concern itself too much with the science of measuring energy usage. Whilst this is an important factor, there is already plenty of research out there which does a much better job of exploring this topic than I ever could. Some of these are referenced in Appendix A.

The climate crisis

The Climate Crisis currently affecting the planet is one of the most pressing existential threats that humankind has ever faced. Carbon emissions caused by years of post industrial human activity is causing Earth's temperature to rise, and we are already seeing the effects of this through an increase in extreme weather conditions, flooding and wildfires, as well as irreversable damage to the polar ice caps.

The current scientific consensus estimates that we will begin to see the worst effects of climate change once the Earth's temperature reaches between 1.5°C and 2°C above pre-industrial levels - effects such as famine, drought and extinction. Alarmingly, these are impacts that will be felt worst in the poorest countries the world - those who have contributed the least in terms of carbon emissions. The science also tells us that once Earth reaches this temperature, some of the effects may be irreversable.

Efforts are being made globally to reduce carbon emissions. Every country in the world has signed up to the Paris Agreement, which is a pledge to stay below the 1.5° figure. Whilst industry appears to finally be waking up to this reality, the change is not happening quickly enough and currently we are on track to reach 1.5° this century, with earliest estimates being as soon as 2030. The only chance we have of preventing this is for all nations to work together and make drastic changes to their environmental policies, industries and to encourage their populations to lead greener lifestyles.

This book makes no further attempts to convince you on the urgency of this matter.

The impact of web applications

Most of the energy cost that websites and applications consume comes through electricity, so we could just kick back and wait for the world to switch to renewable energy right? Leave it to someone else to sort out and just carry on doing things the way we currently are?

Well, No. Not exactly. Firstly, we're not there yet in terms of sustaining 100% renewable energy at a national scale, so anything we can do to both slow the consumption of fossil fuels and reduce overall energy consumption generally is a positive thing. Secondly, there are other costs aside from just the electricity spend, costs such as increased e-waste that our applications may be indirectly (or directly) contributing to. Adopting a more environmentally friendy approach to creating web applications carries many other benefits aside from helping to conserve Earth's resources.

As web developers and digital professionals, we are in a unique position to help reduce the energy footprint caused by our industry. Typically, much of the blame for emissions is aimed at data centers, but we as developers do share in that responsibility because it is our applications that they are hosting. Because there is a direct correlation between the energy impact of digital services and the number of users/visitors that those services receive, a single good decison that we make around sustainability can propogate into huge savings on energy consumption for our applications.

This book aims to highlight some of the ways that web developers reduce the energy footprint of their applications - and the great news is that many of these techniques are simple to implement and usually come with other bonuses, such as faster page load times and cheaper hosting bills.

You may find many of the ideas to simply be common sense... and that's entirely the point. Despite these all (mostly) being well known best practices, they are still things which we regularly see skipped during application development due to the delivery pressures that most developers find themselves under, and any developer will tell you that the first thing that gets sacrificed when the pressure starts to mount is code quality. The aim of this book is to re-frame these best-practices through the lens of sustainability. We have been living in the "age of plenty" with regards to data and compute, and have had the luxury of not really having to worry about how much data we use - what this book is suggesting is that we should pivot towards thinking about the energy cost of every piece of our applications and shift to using our skills responsibly.

Because "sustainabile engineering" is largely synonymous with "good engineering", you'll hopefully find that you're already hitting many sustainability beats with your applications already just by being an awesome developer. With any luck, you will also find some more ideas that will inspire you to make your web application even more environmentally friendly.

This is not about making developers feel guilty for every byte of data they use or every CPU cycle they consume, nor is it about shaming anyone or telling them what they should or should not be doing in their application - It's simply about making energy usage a conscious part of our software development process - and getting started may be a lot easier than you think.

Measuring energy usage

How exactly do you equate a energy footprint to your website or application?

The bad news is that you basically can't. Between the background noise of the measurement itself, unseen factors such as user device behaviors and the inherent opaqueness of hosting providers, getting an exact figure is essentially impossible. The best you can hope for is to get a decent estimate that you are comfortable basing targets around.

The good news is that the factors that cause energy consumption to increase are fairly well understood, so we know what we need to optimise for even if we can't get an exact measurement of the associated energy cost. We can use this information to build a rough model for linking our application metrics to energy usage, and indeed several such models already exist in the wild.

A French think tank called The Shift project created a report a few years ago entitled LEAN ICT: TOWARDS DIGITAL SOBRIETY. In this report, they proposed a model for estimating the carbon emissions of web based applications called the 1-byte model. This model has become fairly prominent in the sustainable IT space and is often cited in the media. Essentially, the one-byte model applies coefficients to several metrics;

  • Where is it hosted?
  • What device is it running on?
  • How much data is it using, both at rest and over the network?

From these, the 1-byte model proposes that you can get an energy estimate for your application. Colleting the metrics associated with these elements is broadly possible using a combination of client and server-side analytics software, but this highlights the earlier point about how "rough" this estimate is going to be. How can you be sure, for example, which device each of your users are using, or how much data usage is attributable to each device? This is made even more difficult by the fact that users are somewhat empowered to hide this information from you! The one-byte model itself often comes under criticism for this very reason, with statements being made about its accuracy and therefore the validity of any measurements derived from it... but is getting a precise measurement for energy consumption really the most important thing here? Of course, most organisations will need to adopt some form of measurement in order to track progress, but optimising is the real goal here and you never hear anyone arguing that the factors this model considers are not the right ones.

There are well established ways of measuring things like CPU cycles and Data Usage - with industry leaders such as ElasticSearch allowing for metric collection to have become "business as usual" for anyone who owns kit either on premises or in a data centre - generally you need to know these statistics in order to keep your systems healthy and to diagnose issues - in some cases, you may even have access to your organisation's electricity bill and be able to see how much energy your servers are consuming. This becomes a lot more difficult if you are hosting within the cloud though as suddenly the energy usage is abstracted away and just becomes a monetary figure. Attempts have been made to create a model for calculating energy usage in the cloud, notably Etsy Cloud Jewels which provides a model for estimating Google Cloud energy usage.

Whilst it may be that we can never see the true carbon impact of our applications, the main messaging around this issue is very clear:

  • Try to use less data and not be wasteful.
  • Try to build efficient, fast applications to optimise for CPU cycles.

The ideas within this book mainly focus on these two aspects - minimise these, and you minimise the electricity consumption of your application. In most cases you will also enocunter side-benefits and will find that by doing this you are inadvertedly optimising for cost and user experience at the same time.

Several organisations and groups have dedicated lot of time into the science behind calculating energy estimates. In particular, the Green Web Foundation have produced some extremely thorough articles on the subject which you should read if you want to dig deeper.

Pitching green initiatives

How do you convince your boss, your colleagues, or even yourself, that reducing the carbon footprint of your web application is a good idea?

In a perfect world it would be enough that reducing energy consumption is good for the planet. We know that the climate crisis is real and that, in varying capacities, we all have a role to play in keeping the situation under control. Realistically though, we need to accept that currently this is a tough sell and that taking action for the greater good might not be enough to convince everyone.

Web applications have no direct, observable impact on our natural landscape, so as developers we don't face the same criticisms as other industries. The fact that websites even have a carbon footprint is completely invisible to most people. This can obscure the benefits of making our our applications more sustainable. Our users won't notice, and we won't see any benefit ourselves, so why should we care?

This is a completely fair challenge - however, it is countered very easily: The digital industry is luckier than many others in one crucial way: Reducing the energy footprint of a web application almost always carries associated benefits. We present some of these here in an effort to help you sell this idea to others.

It doesn't need to be lots of work

People often worry that being environmentally friendly will be expensive, disruptive, and time-consuming. Sometimes these perceptions are absolutely real and can be major blockers to taking action. A development shop is a business after all and most digital businesses are likely to be running very tight deadlines to deliver ambitious features for their users. It is understandable, then, that a company may be behind the idea of being greener in principle but not to the point where they'd consider dedicating any time or resources to it.

Browse through the prompts on this site though, and you will see that many of them represent very small, simple changes that do not contribute any significant overhead to development costs - the only thing standing in the way for many of the techniques is simply a lack of knowledge or awareness. Our prompts are specifically designed as quick-reads to overcome this very hurdle. Even if the only changes you make to your application are the really easy ones, you could still end up making a big difference and seeing huge rewards.

It'll save you money

It's a fact of life that your hosting provider is not in the business of giving out free lunches. The tarrifs for most providers include costs which are directly and proportionally related to your CPU and Data usage. Coincidentally, these are the two major things you need to minimize in order to make your website more sustainable. The upshot of this is that reducing the energy footprint of your web application will almost always also mean a reduction in your hosting costs.

It'll make your users happier

There is a massive crossover between good user experience and good sustainability. Don't confuse your users - not only will they spend less time clicking around your site and wasting battery/consuming data, they are also more likely to have a better experience. Design a clear, unobtrusive user journey through your application and make it fast - you will not only save on energy consumption, you will also make your customers happier.

It future-proofs your organization

The climate crisis is becoming more and more urgent, and it is only a matter of time before the metrics around carbon emissions become a major factor in the day to day running of organizations. Among the factors are:

  • We will see a younger generation of more climate-focussed employees who are more likely to include sustainability policies among the criteria they use to select an employer.
  • Data and CPU might become more expensive. Currently we are seeing prices mostly heading downwards as hosting companies compete with each other to be the most affordable. At some point, legistlation may be introduced forcing hosting providers to invest in more sustainable infrastructure - a cost which they will almost certainly pass on to the customer.
  • Due dilligence in acquisitions could begin to see investors looking for carbon neutrality and sustainable policies as major factors in whether or not to acquire businesses.
  • Browsers may start making carbon usage more visible - there are already plugins that display carbon usage on websites which may one day become standard. If this happens, your users may become more discerning, choosing which companies to buy from based on their digital carbon footprint. Can you risk the reputational damage of being seen as a "dirty" website by your customers?
  • SEO companies such as Google already punish heavier or slower websites in terms of page rank - this means the more environmentally friendly sites will appear nearer to the top of search results. As the world moves towards being more sustainable, failure to act might see you dropping in the search rankings and losing customers.
  • Digital agencies may start to see sustainability featuring high on their customers list of requirements - and even if that doesn't start happening, including it in your pitches is a great way to stand out from the crowd and potentially open your customer's eyes to a value-add they hadn't even thought of.

This list could go on for much longer. Whilst all of the above are just educated predictions (this is the nature of futurology after all) are they really so far fetched? When you consider that making the right changes can be simple and affordable, we firmly believe that it is a bigger risk to ignore these than it is to factor them into your future strategies.

Stay grounded

It's great that you've decided to educate yourself about sustainable web development - we're all going to need to make changes to the way we work over the coming years and this book can help you to get a decent handle on the factors that contribute towards the energy footprint of web applications. The intention is not, however, to make anyone feel guilty for creating digital experiences. There is a temptation, once you know what to look for, to obsess over every single byte of data your applications consume or to agonize over the minutiae of factors that would affect CPU efficiency.

Please try to balance the ideas in this book with reasoned thought when applying them to any situation, and definitely avoid using the ideas as weapons to win arguments with your colleagues. By taking the advice contained herein too far, you risk damaging the user expericnce of your product and driving customers away.

Many of the ideas presented in this book have effects that would be invisible to your users but extremely valuable from a sustainability perspective. This is not always the case - some of these ideas do have a noticable impact on things like image quality, brand identity and user experience. This presents you with a tradeoff: How much optimisation is "enough"? For this, there is a golden rule...

The Golden Rule

Focus on reducing waste, not capability.

If you go into this all guns blazing, insisting that every single byte of data and every single CPU cycle must be preserved at all costs, you risk not only damaging your business but also of losing the hearts and minds of those you are aiming to convince. Make sure all decisions are accompanied by a large dollop of common sense because it can happen that in choosing the most sustainable option, you erode the experience for your developers and users so much that the productivity hit ends up actually increasing the amount of energy consumed by your application.

Many of the more crunchy pain points are related to design, an aspect where many tradeoffs can be made and where "vitalness" to the application beocmes somewhat subjective. Being sustainable does not necessarily mean that your application will be unattractive, but many common design trends tend to lean towards being quite energy-intensive whilst adding only non-functional features:

  • Large, bold images
  • Streaming videos or interactive widgets
  • Transitions and animations

These are all things that will increase the energy footprint of your app, and might improve the user experience, so you can expect any discussions about dropping these kinds of features to become a bit feisty but bear in mind that it is possible to take things too far in either direction. You could, for example, abandon styles completely and leave it all to the browser defaults - this will have a noticable positive impact on your website's energy footprint (yay) but will almost certainly have a negative impact on user experience, possibly even causing your users to believe your site is unprofessional or even that it's broken! It won't, as they say in the business, "pop" any more and this could end up affecting customer engagement and ultimately conversions.

Try to focus on the things that cause the biggest impact from an energy perspective, but which have the least impact to your users. It's not about scrabbling to save every CPU cycle or every byte of data - it is about striking a sensible balance between your appliction's energy footprint and the value it offers to users.

General Tips

The prompts in this section aren't related to no any particular aspect of web development, rather they are broader ideas covering the more strategic and high-level decisions you may need to make, such as how to manage bundle sizes and how to choose a browser support strategy.

Adopt a data budget

Choose a data budget for your application and stick to it. Research such as the lean ITC report by Shift Project asserts that there is a direct correlation between the amount of data an application uses and the amount of energy it consumes.

Here we are specifically talking about the amount of data that needs to be sent back and forth over the wire in order for our application to function - this is a statistic over which we have a large amount of control, but it is often a neglected optimisation, at least until it starts to affect our application's performance (be that our own build times or a perceivable sluggage in the application itself).

The energy footprint of our applications is directly proportional to visitor numbers, so smart decisions about data can result in massive energy savings for our application as the number of users increases. This all carries the added benefits of faster and cheaper overall performance, as your hosting provider is likely charging you by the byte for data transfer.

We're using the term data budget here to describe a limit which you choose to set on some aspect of data usage. One example of this is to measure the amount of data trasfer required before a page becomes interactive (it's so called "time to interactive" or TTI, according to Google's web vitals initiative). This is often called the "page weight", or the number of KB downloaded before the page becomes interactive. The concept of a data budget is not purely limited to page weights however - any part of your application that transmits data — even things that the user never sees - may benefit from the introduction of a data budget.

There are many tools that can show the estimated energy footprint of your application based on the data it uses:

Many of these let you choose a data budget strategy and then enforce it through automation. Doing this needn't be a massive overhead for your team; simply install the tooling, check what your current page weight or bundle size is, add 10%, and that's your starting budget. You can then work towards reducing that budget over time, and—more importantly—making sure you never exceed it without making the conscious decision to do so.

For example: Your team has been looking after a NodeJS application for a few years which relies on several external dependencies which you manage with npm. You examine the size of your post-build bundle and note that it clocks in at around 1MB. You collectively decide that you are going to set a data budget of 1.1MB and aspire to stay underneath that limit for the remainder of the application's life cycle.

Setting a data budget turns data usage into a conversation. Any decision that would cause you to exceed your data budget is now transformed into a conscious decision.

Setting a page weight

You can see what the internet average page weight is using the page weight report tool from httparchive. This lets you break down page weights by type and by date. For example, in 2021 the average web page for the top 100,000 sites on the internet measured approximately 1700KB (or 1.7 MB), of which 540KB were images and 570KB was JavaScript (these are typically the biggest areas for improvement). If you can get under the average then great, but try to be bold in your page weight decisions rather than just shooting to be below the average - 1.7MB is still pretty high for a single page.

You can be as granular as you want to be with your own page weight budgets, either setting a weight limit for the whole page, or setting individual budgets for different aspects of the page (such as an image data budget, a CSS data budget, etc.).

Alternative: Set a "story weight"

Sometimes it won't make sense to use a page weight, so you might instead want to adopt a 'story weight' for your application by calculating the overall weight of a complete user journey, rather than doing it on a page-by-page basis. If we were running a shop, for example, we might choose stories (and budgets) like this;

Story NameDetailBudget
Not what I was looking for!User saw the home page and realised it's not what they wanted400kb
Just browsingUser comes to the site, looks at several products, then leaves5MB
I know what I wantUser is looking for something specific, finds it, and buys it4MB
I want to talk to someoneUser wants to ask a question or make a complaint2MB

As well as being a more realistic way to measure user experience, it also incentivises the creation of a set of core user stories for your application if you don't already have these. As a by product of optimising for these stories, you may find that you start to think more about how to make these stories take fewer steps or how to streamline them in other ways - all of which contributes to creating a great experience for you users.

Other considerations

  • The team developing the app should be the one to pick the budget, since they know the app intimately and are best-placed to pick a sensible or realistic budget. If your company makes multiple apps, don't mandate company-wide page weight budgets. The nature of apps means that some will generate more carbon than others. Don't pit your applications against each other, but of course there is a lot to be gained by ensuring that the channels of knowledge sharing are open between teams.
  • Like many things, you can turn this into a game by giving teams incentive to shed page weight. Everyone enjoys a bit of code golf, right? Think of this as energy golf - but be cautious when adopting this kind of gamification because it can easily become a perverse incentive: ask your developers to shed 1% of their data usage a month, and you may be inadvertedly incentivising them to hold back the big optimisations to ensure they meet can their monthly targets.

Support browsers sustainably

Choose a browser support strategy that is sustainable. At the most basic level, this should include a commitment to support the most modern versions of each browser and a limit for when you stop supporting older versions. The specifics of your browser support strategy are up to you, the main point is to make sure you have one.

There are a few sustainability angles to this;

  • Older browsers don't support sustainable techniques.
  • Some browsers are more memory-intensive / power hungry than others.

The following sections go into more detail on each of these points.

Older browsers lack support for sustainable techniques

Many of the potential gains from sustainable web development depend on modern browser techniques, including:

By supporting older browsers (Notably Internet Exporer 11, Opera Mini, and any browser version released prior to 2018), you risk perpetuating unsustainable web practices.

Perhaps you have commercial reasons for supporting these browsers; your marketing data may suggest a significant loss of custom if you cease support for older software. Also, since modern web applications are meant to be inclusive, you will probably need to accommodate people who find the prospect of upgrading or switching their browser software a daunting task.

Despite what you may think, you are not truly helping your customers by enabling their continued use of outdated browsers (In the case of Internet Explorer, Microsoft have officially withdrawn support). Use of older browsers represents a very real security risk for your customers.

You have a few options for such customers:

  • Refuse to serve them until they upgrade.
  • Continue to cater for them, but encourage them to upgrade their browser. There are tools available to help you do this.

Don't force users to use a particular browser

Websites often advise people to install a particular browser for "the best experience". Sometimes this advice is well-intentioned, and encourages customers to upgrade and use any popular, modern browser. Tooling and algorithms continually strive to be more efficient, so embracing modern software typically results in longer battery life and a better user experience.

Conversely, developers might encourage people to use a specific browser because they don't intend to support the others. As a developer who does this, you must weigh any productivity gains from reduced support requirements against the impact of people being forced to use browsers that consume more resources (and hence more power) than others you don't want to support. Chrome, for example, is an otherwise excellent browser that is frequently called out as being very memory hungry.

  • Can I use? - a comprehensive reference of browsers and the web technologies they support.

Curate features responsibly

Deprecate features that users are not making use of, especially if they are resource intensive. Just because a feature is "cool" does not mean it is also necessary. By maintaining resource-heavy features that your customers are not using, you may be forcing them to download data un-necessarily. Even if the feature can't be deprecated, there may be other ways of achieving the same funcionality at a fraction of the cost.

Example: Mapping functionality

A classic example of a feature that many sites include needlessly is an interactive map, with the de-facto solution being to use Google Maps.

Google Maps is an excellent resource and easily ranks the most fully featured mapping platform in the world... however, at time of writing it is much more data intensive than alternatives such as Leaflet. You can choose which tile set Leaflet uses under the hood but a common option is the OpenStreetMap which is a worldwide collaborative effort to map the world, similar in principle to a wiki.

You can confirm which solution is more data intensive from the network tab of your browser's developer tools - you should see as you interact with a google map that you have much more data being requested by Google Maps than by leaflet (which, at least when I tried this, requested nothing but the new tiles).

There will, of course, be times when you absolutely need to use Google Maps because either you need some of that library's functionality OR you need to do mapping in a part of the world where Google has better data... however, often developers will just default to Google Maps without considering alternatives.

In addition to considering alternative technologies, have you considered not having any mapping funcitonality at all? Maps look absolutely fantastic, but if all that funcitonality is doing is displaying an overhead view of your customer's shop, could you get away with just using a static image? If it's important that users are able to scroll around / interact with the map, how about providing a link to the mapping provider rather than hosting the mapping content yourself? That way, the data cost of displaying and running a map is only paid for by the customers who actually use that feature. If you are absoultely certain that you want a map to appear in-line on your app, consider hiding the feature behind an opt-in mechanism like a button or accordian and only serving the required resources and data to users that activate the feature.

Measuring feature usage

If you are lucky enough to work on an application where you actually get to speak to your customers - ask them about older / resource intensive features. Often people will get very attached to features (especially cool ones!) and deprecating them reduce an application's energy footprint can be a difficult conversation, so you might want to go armed with some statistics demonstrating that a feature is or is not being used.

One way of figuring out usage is via analytics. There are a number of analytics platforms out there that can provide usage data, allowing you to see which features and pages are/aren't being used - popular choices include Google Analytics and Matomo. These platforms allow you to collect anonymous usage data to let you see how your users are interacting with the application. As well as broad statistics such as page visits and journeys, both of these platforms offer fine grained control over the metrics that are collected, allowing you to track custom interactions with individual buttons and controls.

Whilst extremely useful, developers should use these platforms with caution. Currently in the EU and the UK, there are certain legalities around the use of analytics on websites which require you to inform your users when you are collecting these kinds of metrics and invite them to either opt out or leave the site (even if that collect is done anonymously!). In addition to the negative impact on user experience, having these kinds of analytics platforms installed increases the energy footprint of your application because it means you will be sending additional data over the internet. You should only use analytics platforms if you are making active and efficient use of the metrics that are being collecting.

  • Google Maps - A popular mapping platform
  • Leaflet - An open source equivalent to Google Maps.
  • Google Analytics - A popular analytics platform for measuring user behavior.
  • Matomo - an open source equivalent to Google Analytics.

Styles

The following prompts all relate to either stylistic or design choices that you might make when creating a web application.

Create print-specific styles

Have you thought about whether your users will ever print your content onto physical paper? Use print specific styles to apply certain styles only when a page is printed. This allows you to tailor the look of the content to the printed medium whilst also disabling certain sections or elements where it makes no sense for them to be printed at all. Doing so conserves electricity, paper and ink.

Use cases for a print stylesheet

Printing out large areas of solid color can use a lot of printer ink, so most modern browsers will automatically disable the printing of background images and background colors. In some cases this can lead to the printed page losing some of its brand identity, or some elements looking strange becoming unreadable - adding a print stylesheet allows you to correct some of this.

What you use print styles for is very case-specific and it might be that you decide that users are very unlikely to ever print out your application and that none of this is therefore a concern for you. Here are a few ideas to give you a flavour for the kind of thing that they are commonly used to fix or adjust;

  • Making text visible - If you had a block of pure white text on a dark background, the browser may remove the background, making the text unreadable.
  • Maintaining brand identity - your brand might have specific guidelines for how things like logos are displayed when they are black and white.
  • Disabling superflous elements - This might include elements which are not relevant to the content such as headers, navigation, sidebars and footers, but also interactable elements such as buttons and forms - none of which provide any value once printed. Take the example of a recipe website - if someone is printing that page, they probably don't need to print all the links to other recipes you might have placed around the recipe itself.
  • Fixing layouts - most modern websites are built mobile-first and responsive, meaning that a layout should be able to adapt to whatever viewport size it is applied to (paper or otherwise) - however if that is not the case with your application then it might be that your layout prevents the content from being printed in portrait mode.

How to create a print stylesheet

It might be that your application/site works just fine when printed without you having to do anything - you can verify what your page will look like when printed simply by using the print preview functionality within your browser. If it does turn out that you need to apply some print styles, there are a number of ways to do this;

Method 1: Create a seperate print-media stylesheet

Add a stylesheet using the "media"="print" attribute when the sheet is included;

<link rel="stylesheet" media="print" href="styles/print.css"/>

Styles specified by that stylesheet will now only be applied to pages when they are printed.

Method 2: Using media queries

You can put print-specific styles directly into your existing stylesheets using media queries. You can differentiate print and screen styles using the following syntax;

@media screen {
// screen styles go here
}

@media print {
// print styles go here
}

You can also apply logical operators not or only to your media queries if it makes sense to specify things that way;

@media not print {
  // styles not to be applied to print go here
}

Note that if you do this, ensure that you are not including a media attribute when you actually include the stylesheet on the page or this will override these settings.

Method 3: Leverage the capabilities of a CSS library or framework

If you are using a CSS library or framework, it is possible that the authors have already made some print-related considerations and created functionality or documentation to help you work with these styles;

Always consult the documentation for your library or framework before trying to figure out novel solutions on your own.

Paged media properties

It might be that your particular use case falls into the category of being "very likely" to be printed. If this is the case, there are a number of paged media-specific CSS styles that can be applied to elements in order to achieve the exact printed look that you want for your content. These include;

  • The @page media query for per-printed-page styles (normally for things like margins) - also includes support for pseudo selectors such as :first (to target only the first page) and :left/:right to target pages that would only appear on the left/right (depending on the major writing direction for the document).
  • Page Breaks to allow content to be spread across multiple pages more logically.
  • There is also support for more technical typographical concpets such as orphans and widows.

Employ responsive design

Use media queries to create a responsive web application. People are no longer simply uing traditional laptops and desktop computers to consume web applications - the use of devices such as mobile phones, tablets and televisions is now commonplace. As a result, we no longer live in a "one size fits all" world when it comes to designing user experiences. Serving the full-fat version of your web application to your users will not only result in a poor user experience, it may also result serving them a lot more data than they need to, increasing the energy footprint of your application.

Media Queries

Media queries are supported across all major browsers and have been for some time. They allow you to detect certain properties of the device consuming the application, such as whether it has a color screen or (in the case of phones) whether it is oriented landscape or portrait. The feature that media queries are perhaps most famous for though is their ability to detect the width and height of a device's viewport and apply styles accordingly;

@media (max-width: 480px) {
  .hide-on-mobile {
    display: none;
  }
}

Using media queries allows developers to have their applications "adapt" to the viewport, serving lighter versions of their applications which perform better on mobile devices (conserving battery and thus saving carbon) and in some cases can wholesale avoid downloading some of the larger presentational assets altogether. Whilst your huge, striking hero or header image might look great on a desktop application, a mobile user might not appreciate the additional bandwidth cost they are having to pay for an image that is ultimately going to be reized to fit their viewport anyway.

There is a big UX angle to this too: desktops and laptops provide you with a lot of horizontal space and allow you to apply column-based layouts which mobiles do not, and certain elements such as menus and navigation may need to be replaced entirely on mobile devices for usability reasons.

Images

One common "gotcha" with regards to images and media queries is that whilst behavior across browsers will vary, simply adding a display: none css property to an image will often not prevent your browser from downloading that image (you can confirm this using your browser's developer tools). This means that the user still pays the download cost (and the carbon cost) of the image even though they never see it.

There are a number of ways around this:

Approach 1: Make the image a background image

Most browsers will not download an image if you use a css background image rather than an image tag;

<!-- this will still download the image -->
<img style="display: none" src="foo.png" alt="a picture!" />

<!-- in most browsers, the image will not be downloaded -->
<div style="display: none; background-image: url('foo.png');"></div>

Don't simply default to using this approach for all images! The two elements above are not equivalent - the img tag expressly indicates to the user's browser that the image is semantically important to the content, the div does not. This is important from an accessibility perspective because using an image tag allows you to specify things like alt text which will be read out to screen reader users and displayed to anyone who for some reason cannot download the image. This advice works both ways: if an image is purely used for presentational purposes (e.g. as a background to your site header) then it is not semantically important and background-image should be used regardless of what you are doing with media queries - a screen reader user does not need to know that you have a lovely leafy image on the background of your header!

Approach 2: Use the lazy loading attribute

Some browsers will respect the lazy attribute with regards to CSS display: none only load images when they become visible to the user. For more details on this approach see our chapter on Lazy Loading images.

Approach 3: Use the picture element

The picture element is relatively well supported across browsers and allows you to specify which images to load based on media queries, meaning you can provide several versions of an image and allowing your browser to select the appropriate version:

<picture>
    <source srcset="/small.jpg" media="(min-width: 480px)" />
    <source srcset="/medium.jpg" media="(min-width: 1000px)" />
    <img src="/large.jpg" alt="An image" />
</picture>

The browser will only ever download one of the images, meaning you can serve different sizes for different viewports.

Design Mobile First

Prior to media queries, it was commonplace for developers to make two versions of their application (one for standard desktops, one for mobile) They would achieve this using the request's user agent property to figure out whether the request came from a mobile device or not. The rate of change within the mobile market along with the advent of popular tablet devices meant that this approach lasted only a few years before its inability to scale became a hinderance.

Aside from the scalability issue, designing for the desktop first and "cutting back" for mobile is actually a lot more difficult to do because it means that in order to get started on a project, you need to start with the most advanced version of the design and "degrade gracefully" into the more simple version (the mobile version) afterwards. Starting with a mobile design allows us to do the opposite of this: to "progressively enhance". This is not only much easier and quicker, but it also ensures that we do not end up neglecting our mobile users (who are no longer an insignificant portion of our users - figures currently show mobile traffic contributing 52% of all internet traffic!

Use webfonts responsibly

Use web fonts responsibly and lean towards using only natively supported fonts if possible. Whilst modern browsers support many built in system fonts, using web fonts allows you to download and use specific fonts from directly within your application's CSS. This feature been supported across all major browsers for a very long time (as far back as Internet Explorer 6) and there are a few reasons you might want to use it for your application.

  • A particular font might be very important to your brand identity or a major stylistic choice for your application.
  • It might be very important that the site looks exactly the same across all browsers and operating systems (some native fonts are only available on certain operating systems, for example the Tahoma font is Microsoft-developed and therefore not available in some Linux distros).

Including web fonts does require your users to download an additional and not-insignificant amount of extra data, increasing your site's energy footprint.

Using web web fonts

Web fonts are downloaded using the @font-face css rule. This supports several types of file formats including woff2, TrueType and svg.

@font-face {
  font-family: "myAwesomeFont";
  src: url("myAwesomeFont.woff2");
}

Content Delivery Networks (CDNs) such as google fonts will often provide all of the supporting CSS for you, making it very simple to include the font in your application.

It's perfecty fine to use Webfonts

This prompt is not reccomending that you avoid web fonts, only that you use them responsibly and with your eyes open to the data cost. Don't simply choose to use webfonts on a whim - make it a conscious and confident choice and factor the extra download cost into your page weight budget.

If you do decide that you are going to use web fonts, there are a number of things you can do in order to reduce the data cost;

  • Use a CDN - Serving web fonts from a a CDN such as google fonts carries a number of benefits - chief among these being smart caching. Users may have already downloaded the font from elsewhere on the internet and have it stored locally, and any fresh downloads will likely have been cached closer to the user's location.
  • Only download what you need - Some web fonts come with multiple variants (e.g. multiple font weights). You should only download what you are actually using.
  • Consider images - If you are only using webfonts in one place (e.g. the header/logo) then consider using an image with alt text instead - the data cost of downloading an image might end up being smaller than the cost of downloading a web font.
  • Consider using webfonts only for titles and headings - The difference in appearance may be negligable at smaller sizes and reserving web fonts to only titles would mean you could download less variants.

Frontend Code

The following prompts all relate to the code that you run on your client applications. Typically this will be JavaScript, however as of 2022 there are multiple alternatives available in the form of transpilers that use JavaScript as a target (such as CoffeeScript or, more popularly, Typescript). We are also seeing technologies such as webassembly being adopted which allow efficient, near-native compute to occur on client devices.

Choose appropriate libraries

When choosing a frontend framework, explore the alternatives rather than just defaulting to the framework you know or the one that is most popular. Other frameworks may offer smaller, less CPU-intensive alternatives that help conserve batteries and save on data over the wire.

React might not always be the right choice

To cut straight to the chase: many developers will still just use React for everything. In 2022, the React library dominates the UI landscape in terms of adoption and is supported by a huge ecosystem of components and plugins, however you should not simply default to choosing it because it is popular. Weight up the pros and cons of the alternatives and make an informed choice. React is an excellent library, but there are

For people who really like React

Consider Preact.

If you are very attached and bought-in to React or its ecosystem, consider trialling Preact. It aims to maintain parity with React in terms of its API (there are a few differences but nothing major) which means you can try it out simply by using bundler aliases. React and React-DOM combined deploy a runtime that clocks in at around 140kb out of the box (you can get it as low as 40kb if you go to town on optimisation) - you pay that data cost before you write a single line of your own code, simply by choosing React. The runtime for Preact, by comparison, clocks in at just over 3kb.

For people who are happy to learn a new library

Consider Svelte

The battle lines are constantly shifting in terms of runtime sizes, so it's impossible to say which library, at time of writing, has the smallest runtime... or is it? With its revolutionary approach, Svelte presents a new way of thinking about frontend libaries by presenting a compiler-based approach, therefore shipping no runtime at all to the client.

Svelte has also abandoned the virutal DOM approach that dominated the current generation of Javascript frameworks. The Virtual DOM point is an important one from a sustainability perspective because in and of itself it brings no advantages, it's simply a means to an end and causes your client to perform un-necessary work.

Many frontend developers today are already treating their frameworks as if they were compilers (building from the command line, deploying minified artefacts) but are not getting any of the benefits! This is why many people believe that Svelte (along with its contemporaries such as SolidJS) represent the next generation of JavaScript libraries.

Maybe you don't even need a framework?

It is possible, after a time, to get a bit too close to the forest when it comes to frontend development and to forget that it is possible to get things working without using a framework at all. If you can achieve what you need to simply by using plain old JavaScript, and you don't need to worry about scaling up, why not just do that? The data and CPU savings might be huge.

Import efficiently

Ensure that you're importing modules efficiently. You might be unknowingly increasing your build times and serving your users a ton of JavaScript that will never be executed, increasing the energy footprint of your website.

Example: Importing Lodash

Lodash is a popular utility library which provides a collection of useful functions for working with JavaScript. You would be correct in thinking that the following import strategy would be wasteful because it would import the whole Lodash library, even if you are only using a small part of it:

import _ from "lodash";
console.log(_.capitalize("hello world"));

Where many people go wrong though, is in the belief that the following code solves this problem;

import { capitalize } from "lodash";
console.log(capitalize("hello world"));

In fact, this is not true. Both of the above two imports will result in the entire lodash library being imported into your bundle and served to the user. It is possible for bundlers such as webpack to use tree-shaking to throw away dead code, however this feature is normally turned off by default (the reason being that the module may have side-effects that run on import, so it's not safe just to throw code away without asking!).

So what is the solution? In the case of Lodash, the developers have split their functionality up into categories and you can reduce your bundle size by importing only from the category you are using:

import { capitalize } from "lodash/string";

Alternatively for an even smaller bundle you can import only the particular function you are using:

import capitalize from "lodash/capitalize";

Prevention

Whilst the above example is lodash-specific, the principle of importing efficiently holds true for any module you import. Unfortunately there is no "one size fits all" strategy for dealing with this issue as it depends very much on the implementation of the module you are importing - popular UI component library MUI, for example, has a completely different approach to minimizing bundle sizes.

There is therefore no single thing you can do which will cover off all of your imports, but one thing you can do is ensure that you are no longer making assumptions about what does/doesn't make things more efficient through the use of tools.

One such tool is the Import Cost VSCode extension by Wix. Install this into your editor and it will display the import cost for each module in your codebase. This means you will never make assumptions about what is/isn't an efficient import ever again!

Content

Keep content concise

Try to front-load your content, and keep it concise and to the point. The days of packing a page with words purely for SEO are over, and doing so now may actually harm your SEO.

As well as being a good way to engage your users, there are a few sustainability angles to this:

  • Padding content increases page load times and data sent over the wire.
  • In being forced to read excessive text to find something, users are likely to spend longer than necessary on your site, which may reduce their desire to engage or return.

Lazy load content

If possible, try to avoid loading content before it is meant to appear in the active viewport. This applies to content hidden behind a component, or located several page lengths outside the viewport.

Common Solutions

  • Pagination is a simple way to avoid loading hundreds of items on a single page.
  • 'Infinite Scroll' is a popular solution, but beware of accessibility pitfalls associated with this kind of solution.

Avoid excessive markup

Always try to avoid superflous markup, in particular you should avoid adding DOM elements to achieve a particular look or style when there are CSS-based alternatives. Having an overly-busy DOM will affect runtime performance and page speed, as well as contributing to more data being sent to clients. In addition to this, your browser will have to work harder when querying and manipulating a busy DOM, leading to additional battery drain, whilst at the same time harming SEO and accessibility.

An example

Consider a form label, which will default to being an inline element. This means that when rendered, the label will appear to the left of any subsequent input element;

<label for="my-input">Enter some text:</label>
<input type="text" id="my-input" name="my-input" />

Now lets say you wanted that label to instead appear above the form element. Inexperienced web developers may default to trying to achieve this with markup, such as the line break tag (br) or by adding div elements;

<!-- using a line break -->
<label for="my-input">Enter some text:</label>
<br />
<input type="text" id="my-input" name="my-input" />

<!-- using div elements -->
<div>
  <label for="my-input">Enter some text:</label>
</div>
<div>
  <input type="text" id="my-input" name="my-input" />
</div>

Whilst both of these approaches would achieve the desired look, they both involve adding elements to the DOM which do not need to be there. The same style can be achieved using CSS alone, for example by making the label a block level element and adjusting its alignment.

<label style="display:block" id="syled-label" for="styled-input">Enter some text:</label>
<input id="styled-input" type="text" name="styled-input" />

HTML can be minified only by removing whitespace, whereas you will achieve better compression on css because classes and selectors can be programatically obfuscated and optimised - this means that if you default to css, you'll probably end up sending less data to the user.

So you're saying NEVER add markup just to achieve a style?

Definitely not - there will be some cases where, in order to achieve a particular style, you will need to add some additional markup. Material UI, for example, adds an extra span element to achieve the famous ripple effect on elements such as buttons.

There may even be rare cases where the amount of CSS required to achieve a particular style is massive, and you'd end up spending more data than you would if you just added a new element. The trick is just to be pragmatic and make your choices with your eyes open to the cost of your decisions.

Use semantic markup

Where possible, always try to use native browser elements for your web content. Reaching straight for widgets and plugins will lead to an increased bundle size and possibly an Excessive DOM. This will mean your browser has to work harder on queries whilst also increasing the amount of data you are sending over the wire - both of which contribute to an increased energy usage and battery drain.

Semantic Markup

Today, the web platform provides a wide range of HTML elements for you to use when creating content for the web. Having a healthy working knowledge of these tags is undeniably useful, but even the most experienced web developers can still encounter tags and features that they've never used before or didn't know existed.

Did you know, for example, that there is a date input that is natively supported accross all major browsers? And that it can be styled to suit your application?

<label for="my-date">Pick a Date:</label>
<input type="date" id="my-date" name="my-date" value="2021-09-30" />

Whilst using semantic markup does not always mean you are safe from an accessibility perspective, using semantic markup will normally get you most if not all of the way towards being inclusive and is strongly encouraged. Any shortcomings in screen reader browser support are likely to become better over time, meaning that using semantic markup is also an effective way of future-proofing your site.

Widgets, Components and Plugins

If you do reach a point where you have exhausted all native browser options, you may find that it's time to reach out to the open source community to find an appropriate plugin/component. Javascript has a huge ecosystem and there is a lot of choice - here are some things to look out for;

  • Evaluate the popular ones first. It's not all about github stars and npm downloads, but as a general rule the components with the most stars/downloads are normally the better ones, so start with those but don't just default to them.
  • Check that the component you choose is accessible - they will normally state this in their documentation.
  • Don't use a sledgehammer to crack a nut - if a plugin provides 100 features and you only need one of them, you are probably going to be downloading (and serving to your users) a lot more code than they are actually using, contributing negatively to your page weight.
  • Just because a component looks good doesn't mean it is good. Take a look at the markup the component generates before making a decision. Are there problems that could be fixed? Would this component be perfect if it just had one more feature? Consider getting involved with that component's development and submimtting a pull request to the creator. Just because a component doesn't do quite what you want it to does not mean that you need to always choose second best.

There is an online convention known as awesome lists which you can use to browse your options. If you find (or create) a great component that is not on one of these lists, consider submitting a change request to get it added.

Images

Images often make up the lions share of the resources a user needs to download when accessing a client application. This seciton covers some of the techniques you can use to alleviate this cost.

Lazy load images

Defer the loading of images until they are within the active viewport. This avoids paying the data cost for images the user never sees.

Lazy image loading used to be fiddly to implement, requiring an understanding of JavaScript. However, it is now natively supported across all major browsers and requires no programming knowledge. Simply assign the "lazy" property to the loading attribute of the img tag, e.g.

<img loading="lazy" src="/foobar.jpg" alt="bar baz" />

This change ensures the request for foobar.jpg is only sent if the image becomes visible to the user (either through the user scrolling to the image's location or if the image becomes un-hidden, perhaps by a CSS rule). This technique is supported by screen readers, and also works for iframe tags.

Since this technique will degrade gracefully into older browsers, there is little reason to not use it. The behavior of this feature can vary between browsers, so you should make sure to test your assumptions and make sure your application is not erroneously sending off requests - you can do this using the network section of your browser's developer tools.

Never use GIFs

Instead of animated GIFs, use the HTML5 video element to stream MP4 videos. The file size of a GIF can be quite large even for very short videos, and a near-identical effect can be achieved with a much smaller MP4 file. The following HTML will look exactly like a GIF to users, but is actually a muted MP4 set to play automatically and loop indefinitely.

<video autoplay loop muted playsinline>
  <source src="/media/video/my-video.mp4" type="video/mp4" />
</video>

The only way most users would realise this was a video is if they right-clicked it, at which point they might be thankful for the additional versatility of the format, including options to pause and rewind, view full-screen, or even "cast" the video to other devices.

The video above was originally a GIF almost 2MB in size. After an online tool was used to convert it into an MP4, the file's size dropped to less than 100k. Since video data will be streamed to the user and not downloaded in full like a GIF, the user only pays the data cost for what they actually view.

Be aware that MP4 Videos do not support transparency like GIFs do; if transparency is required, consider a modern format with better compression such as WebP or AVIF, both of which support animation and transparency.

Other things to consider:

  • If you leave the video's controls enabled, users can decide whether to play it at all, helping them avoid unwanted data costs.
  • Multiple other video formats are supported.

Resize images appropriately

Don't serve images that are bigger than they need to be. Larger images mean larger files, resulting in more data traffic. If possible, you should pre-resize the image on the server so the user's browser downloads it in an appropriate size.

It is common in web development to have the browser render images in dimensions much smaller than those of the original file. This can be done using CSS or the width and height attributes of an image tag. At best, this means scaling by a few hundred pixels to help an image fit a given layout, but at worst it can mean images thousands of pixels in size being rendered as thumbnails.

Such extreme rescaling forces users to pay the data cost of downloading an image they may never see at full size and, depending on the image's format, that cost can be steep. This is especially problematic for mobile devices, where smaller screens require smaller images, and users' data allowances might be limited and expensive.

Resizing images

Resizing images need not be a tedious manual task; if you can identify images on your server that are larger than required, you can automate the resizing process. There are many tools available to help you do this, including ImageMagick, which makes resizing images as easy as:

convert person.jpg -resize 64x64 person_thumb.jpg

ImageMagick also includes the mogrify command, which is similar to the convert command above but works on batches of images.

Handling different sizes for different viewports

If you know your user's screen is only 500 pixels wide, you probably don't need to serve them huge image files. Historically there was no decent solution to this issue, but that is no longer the case. The HTML5 picture element can be used with media queries to ensure only appropriately sized images are requested, e.g.

<picture>
    <source srcset="/foo_500.jpg" media="(min-width: 500px)">
    <img src="/foo.jpg" alt="Bar" />
</picture>

The picture element is supported across all major browsers. You can set your own thresholds depending on the target viewport width; screen widths can vary significantly between devices, but mobile phones typically don't have a screen width greater than 450 pixels at time of writing. Most modern browser developer tools let you simulate mobile devices, letting you test the functionality without needing the physical device itself.

Use appropriate image formats

Always try to use an appropriate format for the type of image you are working with. Photographs work well in lossy formats such as JPEG, but if you want to draw a logo or similar in different sizes and colours, SVG may be more appropriate.

Here's a short list of other recommendations. Note that WebP and AFIV are both versatile enough to fulfil multiple roles, and normally offer 20-30% better compression than alternatives. Where feasible, you should use vector graphics.

Image TypePreferred FormatFallback Format
PhotographyWebP, AVIFJPEG
Flow DiagramSVGWebP, AVIF,PNG
AnimationWebP, AVIFGIF
TransparencyWebP, AVIFPNG, GIF
LogoSVGWebP, AVIF, PNG
IconSVGWebP, AVIF, PNG

Choosing an inappropriate format can result in image files much larger than they need to be (sometimes hundreds of times larger).

Be cautious using the AVIF format; whilst it is intended as a successor to WebP, current tooling and browsers are not yet mature enough to fully support it, so you need to provide fallback images within your pages using the HTML5 picture element.

Make use of modern image formats

WebP is a next-generation image format developed by Google and can be used in place of earlier formats such as JPEGs, PNGs and GIFs. The WebP format offers 25-35% compression over older formats and is supported by all major browsers. The WebP format includes support for;

  • Animation
  • Transparency
  • Lossless and Lossy formats
  • Transparency

Conversion from other formats into WebP will almost always result in a reduction in size without having to compromise on quality, and there are a number of tools out there which can handle the conversion for you, such as ImageMagick and the official Command Line Tool.

AVIF

A successor to the webP format already exists in the form of AVIF which promises even better compression, however AVIF browser support is not yet mature enough to use it without a fallback image (see Compatibility below).

Compatibility

Whilst WebP is supported by most modern browsers, you may still want to include a fallback format in case you want to cater for older browsers. You can use the HTML picture element for this purpose;

<picture>
  <source srcset="/my-image.webp" type="image/webp" />
  <img src="my-image.jpeg" alt="A picture of a cat" />
</picture>

This will detect whether or not browser support exists for WebP and, if it does, the browser will use the WebP image in place of the JPEG (the JPEG will note be downloaded at all). The picture element also has near universal browser support.

Backend Code

This section covers some of the things you can do on the back-end of a web application (meaning things that you can do on the server) in order to reduce your energy footprint.

Use the right kind of database

Don't default to creating a backend server or a database if you don't need to. There may be alternatives, such as a JAMStack, static JSON file or just plan old HTML, which in combination with cloud-based online services could provide the functionality you need without the many overheads (environmental and otherwise) of running your own servers.

The Problem

All too often, developers will reach straight for popular stacks or familiar stacks for everything. Stacks such as;

  • LAMP/MAMP (Linux/Mac, Apache, MySQL, PHP) - arguably the stack that popularized "stacks" in web development.
  • LYME (Linux, Yaws, Mnesia, Erlang)
  • MEAN/MERN/MEVN (Mongo, Express, Angular/React/Vue, Node)

These stacks are popular conventions and there will of course be times when these are the perfect solution - a LAMP based solution, for example, provides a simple deployment model that can easily be performed by people with very little technical experience. This gives everyone the ability to deploy "out of the box" solutions to common problems.

Oftentimes though, these stacks are used by default without considering alternatives. LAMP-stack based library Wordpress, for example, reportedly powers 42% of the web and has a huge and vibrant ecosystem. There's no disputing that Wordpress is an excellent CMS, but how many of those sites are just a couple of static pages and a contact form?

The Alternative

Consider the aforementioned scenario, where a customer simply wants some static content and some kind of form, maybe one that sends emails. You can achieve this using static HTML and some online services;

  • If the customer will never be editing the content themselves, why plug in a CMS? You could either just hard code the static content, write it in Markdown files or even put it into a local JSON file.
  • If the customer wants the ability to edit content themselves, consider providing this feature through a cloud based content platform such as Sanity.io.
  • If the customer wants a contact form, the hosting provider Netlify provides hosting for static sites, plus the abiltiy to create custom forms to collect feedback. Alternatively you could use an email platform such as SendGrid.

The tooling around JavaScript is so good these days that implementing the above might not be as tricky as you would think. On top of this, most online services will be run out of the "big three" cloud providers (Microsoft, Google and Amazon) who all have made sustainability pledges and are comitted to moving towards 100% renewable energy. Cloud based solutions often also implement sustainable scaling strategies to ensure their resources are being used efficiently.

It'll probably cost quite a lot less than running a server 24/7 too.

JAMstack

JAMStack (Javascript, APIs and Markup) is a modern approach to creating web applications where you handle the layout, functionality and content on the client using JavaScript and Markdown. Any functionality that cannot be handled on the client (such as sending emails) is handled using APIs, be they either online services or APIs you write yourself.

The advantage of all this is that you don't have a server running around the clock waiting for requests that may never come. Popular JAMStack frameworks include Next.JS, Gatsby and Hugo.

Databases

On the database front, oftentimes people will spin up a database server purely because they believe that is the only option for storing data... but you might be able to get away with a simple JSON file containing the whole database. This could then be cached locally (depending how big it is) and hey presto - all data access is happening locally and no data is being sent over the wire.

If you are working mainly with static data

  • That changes infrequently
  • That is only really edited by power users or developers
  • With simple access patters such as "get by id" or "filter by category"

Then you probably don't need a database - another carbon (and money) expense you can get rid of, plus another boost to your application's performance. Choosing JSON as a format also means you have an easier path to migrate to a database should you ever decide you need one, as JSON is the format used by popular solutions such as MongoDB and CouchDB.

It's also one less security concern for you to worry about, as online providers will often take care of data protection concerns such as backups and data integrity for you.

  • JAMStack.org - A comprohensive guide for building JAMStack sites.
  • StackShare.io - see what stacks other companies are using.

Choose a green host

When choosing a host for your website or application, check the provider's green credentials. Have they made any kind of pledge or statement about their sustainability policies? Do they use only renewable energy suppliers themselves? If not, it might be better for you to take your business elsewhere.

Switching to a greener hosting provider does not necessarily mean that your costs will go up. At time of writing, renewable energy is actually undercutting fossil fuels in terms of price and that trend is forecast to continue. Not moving to a green host now may in fact end up costing you more in the long run.

The Green Web Foundation maintains a database of green hosts and provide a tool that can be used to check whether any website is hosted green. Ensure that you read the status description given by GWF tool carefully - just because a host does not evaluate as "green" does not necessarily mean that it isn't hosted green, it could just be that a database record doesn't exist for it yet.

You should try to always ensure that your application and its infrastructure is as portable as possible and try to minimize vendor lock-in. This will allow you to swap hosts easily and with minimal disruption, making the decision to migrate to a greener provider trivial. High levels of portability can be achieved through the use of containerization and abstraction through libraries.

This site is currently hosted on Netlify. Netlify have published a Sustainability Pledge publically and use AWS under the hood. Not only are AWS committed to being 100% renewable by 2025, they have alerady achieved this in some European sites such as Frankfurt.

Being able to say that your applications are hosted by green providers is one of the most basic yet powerful statements digital companies can make in terms of its own sustainability policies. Finding out whether your provider has a sustainability policy is just a google search away. If they do not mention sustainability in any of their literature, contact customer support to ask them about it. If the host has no green policies, you should seriously consider switching to a different host.

Cloud Provider sustainability pages

Optimise data queries

When querying for external data, ensure that your requests are efficient and inexpensive by only requesting what you need and caching agressively. Requesting excessive amounts of data will not only slow your application down, it will increase its energy footprint. The following is a list of common mistakes to look out for;

External APIs

Making optimisations for queries to external APIs is particularly important because these services are often rate-limited so on top of the carbon cost and the slow response times, you may also be burning through your quota faster than you need to!

  • When querying an external REST API, check whether the provider allows you to specify which fields to return. If it does, ensure you only ask for the fields you need. If the external API implements the JsonAPI specification, it may have this functionality by default (see JsonAPI compound documents).
  • Don't send the same query to an API endpoint multiple times if that data is not likely to have changed. Reference data such as categories should be cached locally if possible.
  • If the API is graphQL based then you will be able to request associated records in a single query - graphQL always allows you to do this by design.

Databases

It is equally important to optimise queries that go directly to a database.

  • If using an RDBMS, never select * from table unless you are going to be using every single field on that table.
  • If using a NoSQL database, never scan the whole table unless you are planning to use every single record that is returned and have no alternatives. As a general rule, if you are finding that you are having to do this then it probably means there is a problem with your database design - you should optimise for the access patterns you are going to need.
  • Consider pre-calculating aggregated values such as sums, counts and averages. Rather than re-computing these values every time the user asks, you could just calculate them once every time a new record is inserted. Doing this will also mean that you can be confident that your database will scale.

N+1 Queries antipattern

The N+1 queries antipattern occurs when you have a query nested within the items returned by another query and is usually encountered when you are querying for associated records within an existing list of records. To illustrate this, imagine you are creating a blog with the following one-to-many relationship;

A post has 1 author
An author has many posts

You can easily get "all blogs" in a single database or API query, but if you are not careful you may end up requesting the author details for each blog post you returned individually (hence the name N+1 - N queries for authors plus the original 1 to get the post).

Your code can be affected by this whether you are querying from a REST API or connecting directly to a database and can sometimes be obscured if you are using a client library to handle the query for you. It is always important to keep an eye on your logs to make sure you are not sending an excessive number of queries.

In terms of avoiding the problem:

  • If this is an API that you do not have control over, check whether other endpoints are more appropriate or whether functionality exists to return the data you need in a single query. If you do have control over the API, ensure that the funcionality exists to serve the requests you want to make.
  • If this is a database, you should optimise queries for the access patterns you require - in an RDBMS, this may mean making one query that aggregates multiple records together into one.
  • You are particularly susceptible to this issue if you are using an ORM library because those libraries explicitly try to hide the complexities of a query from you. Inexperienced developers may find that they are sending N+1 queries without even knowing! ORM libraries should always provide functionality to get around the issue, such as the eager loading funcionality in ActiveRecord from the Ruby on Rails ecosystem.
  • If you are building a GraphQL API you will almost certainly encounter this issue as your users will, by design, be able to query associated records for every data type in your schema. Because this issue is so common, a batching-and-caching library called DataLoader was created to deal with this very issue.

Optimize your API

Minimize the amount of data returned by a single API request by allowing users to customize what you send to them. There are many ways you can do this:

  • Pre-aggregate metrics such as counts and averages so your user doesn't have to do these calculations themselves.
  • Empower your users to only request the data they actually need for a given use case, for example specific fields or specific quantities.
  • Allow your user to pre-fetch related records in the same request.
  • Make sure there are ways for the user to download and cache reference data such as categories.

If you ensure that your users can minimize the amount of data they request from your API, you will save data and reduce the energy footprint of your application not only for your own customers but also for your customer's cutomers.

Example: A Blog with comments

Suppose you are creating an API for a blog with comments - a poor API might expose an endpoint like the following example as the only way to get a list of the blogs for a given month;

GET /posts/?year=2021&month=10
[
  {
    "id": 1,
    "title": "My first article",
    "date": "2021-10-10",
    "body": "This is the full body of the artilce"
  },
  //... ALL posts follow
]

In order to find the comments for this post, the user must send away a second request to the comments endpoint;

GET /posts/1/comments/
[
  { "author": "Fred" , "comment": "I totally agree"},
  { "author": "Barney" , "comment": "Good post"},
]

Let's say your customer is creating a "browse posts per month" feature for their site. To do this, all they need from your API is the title, the date and the number of comments for a given month - they also want to paginate through 10 posts at a time. With no way of preventing all of this data being sent back, the user is required to make a potentially large request for all the blog data, and then another request per post to get the comment count - this will all include data they do not need.

Now imagine you used a different model and gave the user some control over what they received in the response and pre-aggregated the comment count such that it could be requested directly via the blog endpoint;

GET /posts/?year=2021&month=10&fields=title,date,commentCount&skip=0&take=10
[
  {
    "title": "My first article",
    "date": "2021-10-10",
    "commentCount": 2
  },
  //... more posts follow
]

Through our API we have allowed the user to use the querystring of the request to fine tune the amount of data we return - they request only specific fields (using the fields key) and to specify the number of records they want to return (through the skip and limit keys). No more data being wasted, plus this will likely save compute time and thus speed up the request.

In addition, doing this also gives us confidence that our API will scale because we can now predict (and set limits on) the amount of data a request might return - on our original API implementation, a single month may have many blogs (a metric we might not have control of) and each blog may have many comments (a metric we almost certainly do not have control of!) - that's potentially a lot of data!

Using a specification

Whilst you can design a bespoke API that is optimal for your users, there are a number of specifications out there that provide the recommended optimisations and more out of the box: two in particular are JSON-API and GraphQL.

Both of these provide, by design, implementations that allow users to only request the data they need and offer conventions for patterns such as pagination and pre-fetching related records.

As well as giving you a battle-tested pattern to base your API around, your customers are also likely to thank you for the improved developer experience they receive when consuming your API: Not only are responses now tailorable, they are also predictable and because both JSON-API and GraphQL are schema-based. This means that you can auto-generate your documentation and your API consumers can auto-generate much of their client code!

Use the right kind of database

Choose the correct type of database for the job you are doing. By defaulting to popular or familiar database types, you may be missing the opportunity to optimise metrics such as data size and CPU usage, subsequently increasing your energy footprint.

For many years, relational databases such as Postgres, SQL Server and MySQL have dominated the online database landscape. As the web has matured, certain patterns and use cases have emerged for which relational databases are not an ideal fit. Eventually these patterns became common enough to spawn database architectures specifically built around those use cases.

Examples of modern database paradigms include;

Database TypeExamplesUse for
RelationalPostgres, MySQL, SQL ServerTraditional information systems with unpredictable access patterns
Key-ValueRedis, memcachedCaching, Queues, Leaderboards
Document StoreMongoDB, ElasticsearchSemi-structured document-oriented data
Graph DatabaseNeo4JFraud Detection, Recommendation Engines, highly relational data

The decision around which database to use is highly case-specific, but the core principle is not to simply default to the popular or familiar choice. Look at your requirements and choose a database based on those - this might involve doing some research to see how other people solve your particular problem. Think about whether things like high-availability or burst-traffic scalability are important to you (in which case, SQL might not be the best choice due to its inability to scale easily) or whether or not you can identify all of your access patterns up front (and if not, SQL probably is a good choice due to its flexibility).

Even within each database paradigm there are decisions to be made around which product to use, prompting more research. In the case of Key-Value databases for example, there are important differences between Redis and memcached that might make you choose one over the other;

  • Redis allows you to persist your data to disk (memcached cannot do this without plugins).
  • Memcached is multithreaded, allowing you to handle more operations at once on multi core computers.
  • Redis is very feature rich, whereas memcached just does one thing well.
  • Memcached benchmarks faster on writes, although has parity with redis on reads.
  • Whilst both databases are supported in multiple languages, wider support exists for Redis.

It's also about making your own life easier. Opting for a graph database, for example, brings with it all the graph algorithms you might need such as measures of centrality and distance, or the ability to find clusters. Whilst you could model your graph data within a relational database, this would then require you to write all these algorithms yourself should you want to use them. Not only would this take up a lot of time and effort, your own implementations are unlikely to be as efficient as those provided by a database specifically architected for that kind of task.

Using certain database paradigms also opens up the opportunity to adopt a serverless architecture - AWS DynamoDB and Azure CosmosDB are both highly scalable NOSQL databases that offer serverless, consumption-based plans - this means you only pay for what you use, but also that you don't have a database server running 24/7 burning electricity when you're not even using it.

Appendix A: External Resources

Links to fellow knowledge-sharers in the field of sustainable web development. Please take the time to read these — this book covers ways to reduce network traffix, data and CPU usage, but for a broader look at the topic we recommend these resources:

  • Sustainable Web Design - A selection of strategies and advice around sustainable web design, covering technical as well as non-technical aspects.

  • Principles.green - The Principles of Sustainable Green Software Engineering are a core set of competencies needed to define, build and run green software applications.

  • The Green Web Foundation - An organisation offering tools, datasets and services within the field of green internet. One dataset in particular is an effort to curate a list of hosting providers that use renewable energy.

  • The Green Web Foundation on Github - Selection of open source software by the green web foundation. Includes a javascript library for calculating CO2 emissions using the shift project 1-byte model.

  • Sustainable Web Manifesto - A manifesto for a sustainable web - signed by almost 2000 people.

Useful tools

A number useful tools available to help measure and optimise your applications.