JWJames Wallis

SEO and Image Optimization with Next.js

2nd August 2020

This blog is part of a series where I document rebuilding a website that relies on HTML, CSS and Bootstrap in React.js using the Next.js framework to improve performance, reduce costs and increase my workflow for future changes.

The finished website: https://wallisconsultancy.co.uk The source code: https://github.com/james-wallis/wallisconsultancy

Want to track users of your website in real time? Check out my post about Google Analytics and how to use it with Next.js.


For a website to rank highly on Google and have the best chance of generating business, it needs to perform well and be SEO friendly. Fortunately, Next.js has two plugins that can help take our website to the next level.

Now that the Wallis Consultancy website has been re-built it’s now time to focus on the finer details which are:

  • SEO specifics (Page titles, descriptions, Open Graph)
  • Image Optimisation (Ensure images are as small as possible, load smaller images on mobile, decrease load times)

We can achieve this easily with Next.js and two third party modules. These are:

With the release of Next.js 10 a built-in image optimisation component has released. Checkout my article where I briefly compare it with next-optimized-images.


Next-seo provides the ability to configure SEO focused fields, such as title, description and canonical URL that are found in the <head> of a HTML document.

It works by adding a <NextSEO> component into a page and passing it props. An example of this for title and description:

import React from ‘react’;
import { NextSeo } from ‘next-seo’;

export default () => (
      title=“Simple Usage Exampledescription=“A short description goes here.”
    <p>Simple Usage</p>

For some attributes, they don’t change on a page by page basis so next-seo provides the DefaultSeo component that can be added to a Next.js _app.js. An example of this is using the twitter and openGraph props:

import App, { Container } from ‘next/app’;
import React from ‘react’;
import { DefaultSeo } from ‘next-seo’;

export default class MyApp extends App {
  render() {
    const { Component, pageProps } = this.props;
    return (
            handle: ‘@handle’,
            site: ‘@site’,
        <Component {…pageProps} />

For wallisconsultancy.co.uk the default next-seo is:

	titleTemplate={‘%s | Wallis Consultancy’}
  		type: ‘website’,
      locale: ‘en_IE’,
      url: ‘https://wallisconsultancy.co.uk/‘,
      site_name: ‘Wallis Consultancy’,


This package optimises all images in a Next.js application by using require('filepathToImage') as the value of the src attribute in an img tag. It is able to handle jpeg, png, svg, webp and gif file types and can also enable progressive loading and inline small images in addition to reducing their size between 20% to 60%.

As described in the documentation, you need to install additional packages to next-optimized-images to take advantage of its optimisation power. As wallisconsultancy.co.uk contains JPG images I also installed imagemin-mozjpeg, webp-loader, responsive-loader and sharp. The latter two packages enable the ability to resize images into multiple sizes at build time - meaning mobiles can be sent smaller images than desktops resulting in faster load times on slower, mobile networks. The webp-loader package is a tool that will generate a webp type copy of the initial jpg image to be shown on devices that support it. webp is a next generation file type that has superior file compression to jpg making them smaller in size and faster to load onto the page

An example use for the image on the wallisconsultancy.co.uk homepage is:

import Layout from ‘../components/layout’

export default function IndexPage() {
  return (
    <Layout pageTitle=“Home”>
      <div className=“flex flex-col md:flex-row”>
        <div className=“w-100 md:w-2/3”>
        <div className=“w-100 md:w-1/3 flex items-center justify-center”>
            <source srcSet={require('../images/mike-wallis2.jpg?webp')} type="image/webp" />
            <source srcSet={require('../images/mike-wallis2.jpg')} type="image/jpeg" />
              alt="Mike Wallis"

This will create 2 compressed copies of the image, jpg and webp. The device will attempt to select webp but fallback to jpg if it isn't supported. On a device where the picture tag is not supported, the img tag will be used.

Google Lighthouse

Lighthouse is an open-source, automated tool for improving the quality of web pages. You can run it against any web page, public or requiring authentication. It has audits for performance, accessibility, progressive web apps, SEO and more.

Google Developers

Before adding the packages used in this blog, the performance score for Wallis Consultancy was around 70 (mainly as the images sizes were not optimised and not using next generation formats such as webp) and the SEO was 60.

After adding the SEO fields and optimising all the images on the website it achieved an almost perfect Google Lighthouse score: The Google Lighthouse score for wallisconsultancy.co.uk


This blog demonstrated the power of two third party Next.js packages next-seo and next-optimised-images. The former will ensure all the pages are setup to rank highly on search engines and the latter makes each page load that little bit faster.

In the next blog, the final of the series, I’ll create a Travis pipeline which will deploy the website to Github pages.


Improving website SEO and performance is a great way to gain more users. Once this is done it’s a good idea to track them and see how real people use your website. Let me take you through adding Google Analytics to your Next.js app to be able to see this information and more.

Adding Google Analytics to Next.js with FAQs.

React, comment and follow on