Using Google Fonts with next.js


The web has come a long way, but getting your font to show up on your site without flashing and not blocking rendering can be tricky. Google Fonts now supports "font-display: swap;" which is a great way to make sure that your page loads and if for whatever reason the custom font doesn't load it falls back to a system or other local font.

How to get google fonts working in Next.js

For Next.js there are two main ways to load your font:

a) add the font locally

b) pick a font that can be loaded from a performant CDN like Google Fonts

For our example we'll use the font that's on this site Noto Sans. Adding the font locally in Next.js is as simple as adding it to the public/ directory. eg in this case we added /public/fonts/noto-sans-v9-latin-regular.woff2 which will automatically be picked up by next and served at /fonts/noto-sans-v9-latin-regular.woff2 (without the public prefix). You can also serve any other static files from your Next.js application from this public directory. The second thing we have to do is add the font to the document (in pages/_document.js) head like:

// /pages/_document.js

import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';

class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
          <Main />
          <NextScript />

export default MyDocument;

Then you can add the @font-display css instruction to set the base font in another part of your application. The exact location of the css might differ depending on what css-in-js solution you are using, but for the built-in styled-jsx one option is to simply create a global style tag that sets the font like:

// /pages/_app.js

import App from 'next/app';

class MyApp extends App {
  render() {
    const { Component, pageProps } = this.props;

    return (
        <Component {...pageProps} />
				<style jsx global>{`
			      @font-face {
			        font-family: 'Noto Sans';
			        src: url('/fonts/noto-sans-v9-latin-regular.woff2');
			        font-weight: bold;
			        font-style: normal;
			        font-display: swap;

export default MyApp;

We ran some performance checks of using the google api to load the font vs Zeit's CDN form the public folder, and they seemed about the same (although Google was a bit snappier in some regions).

Typography without Flash of Unstyled Text

You should note that when setting up typography a common issue is the so-called "flash of unstyled text". This is when the end-user can see some text before the actual font is loaded. font-display: swap; does have the drawback of flashing this unstyled text if the font has yet to load. There are several other strategies you might consider depending on how fast the CDN you are pulling the font from is a good summary can be found on CSS tricks.

Basically there are four strategies you need to consider:

Why google fonts

Google Fonts as really made it much easier for sites to get custom fonts up and running without much headache. The selection is quite vast and their CDN is fast. However you do need to be a bit careful about the font-display issues discussed above when building a site.

Really the reason to use google fonts is the CDN speed. You could easily load another custom font in the Next.js public/ directory as we have done, but the Zeit CDN is somewhat lower coverage than google's so you will experience somewhat higher instances of the FOIT / FOUT issues.

A very good an extensive resource on font-loading can be found here by Zach Leat.

A great tool for getting the css font-display snippet for Google Fonts can be found at Google Webfont Helper. This has snippets for eg our Noto Sans like:

/* noto-sans-regular - latin */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
	font-display: swap;
  src: local('Noto Sans'), local('NotoSans'),
       url('/fonts/noto-sans-v9-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
       url('/fonts/noto-sans-v9-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */

That can be used to target Noto Sans in modern browsers. They also have some support for older browsers as well if you need to support them.