geoff-young

šŸ“šŸ“žšŸ“¹šŸ’»
Prevent Next.js 500 error with proper 404 page configuration
Created
Sep 20, 2021 05:44 PM
Property
blog

Are you using incremental static regeneration? Is your Google search console indexing 500 error pages?

If you have a web app with pages that change location or get removed, you might be generating 500 error pages with Next.js. Google will keep these pages indexed unless you return a 404 page.
Typically with a statically generated site, you only generate pages on build. In this case, with Next.js you can useĀ fallback: falseĀ in getStaticPaths. Any page/address not built returns 404.
import API from '@aws-amplify/api'
export default function UserPage({ user }) {
  return <div>This is {user.username}'s Page</div>
}
export async function getStaticPaths() {
  const getAllUsers = await API.get(process.env.NEXT_PUBLIC_APIGATEWAY_NAME, "/getAllUsers")
  const paths = getAllUsers.body.Items.map(user => {
    return { params: { id: user.Username } }
  })
  return { paths, fallback: false }
}
export async function getStaticProps({ params }) {
  const getUserInit = { body: { username: params.id } }
  const getUser = await API.post(process.env.NEXT_PUBLIC_APIGATEWAY_NAME, "/getUser", getUserInit)
  return { props: { user: getUser }, revalidate: 1 }
}
The code above returns a very basic user page. But if a user creates a page after the build, going to that new address will return a 404 page.
To prevent this we need to changeĀ fallback:Ā to eitherĀ trueĀ orĀ "blocking". So when that new page gets visited, ifĀ fallback: true, a prerendered page (that you make) will be returned while the new page is built in the background. I'm not a fan of returning a page only for it to be quickly replaced so I useĀ fallback: "blocking"; it acts like SSR and builds the page while you wait.
export async function getStaticPaths() {
  const getAllUsers = await API.get(process.env.NEXT_PUBLIC_APIGATEWAY_NAME, "/getAllUsers")
  const paths = getAllUsers.body.Items.map(user => {
    return { params: { id: user.Username } }
  })
  return { paths, fallback: "blocking" }
}
So now when we visit that new page we actually get the new page, albeit a little slower to load. But now if you go to a nonexistent page, it 500 errors, not 404. This causes problems with Google Search. Say a user creates a page, then deletes it - Google will keep the page indexed despite returning a 500 error.
notion image
Once a user deletes their page, we don't want it showing up in our Google search results. We need the page to return 404.
We can do this in Next.js by returningĀ notFound: trueĀ inĀ getStaticProps()Ā when the user doesn't exist.
export async function getStaticProps({ params }) {
  const getUserInit = { body: { username: params.id } }
  const getUser = await API.post(process.env.NEXT_PUBLIC_APIGATEWAY_NAME, "/getUser", getUserInit)
  return getUser ? { props: { user: getUser }, revalidate: 1 } : { notFound: true }
}
The behaviour of the app is as follows:
  1. You browse to talktree.me/deletedUser
  1. If the page exists on Vercel's CDN, it is served from there
  1. This page is not on the CDN, so its built while we wait (fallback: "blocking")
  1. The page is built but the user doesn't exist so a 404 page is returned (notFound: true)
Below is what we want to see when indexing a non existent page.
notion image
Now that the 404 page is being properly served, you can customize it by creating a 404.js file in your pages folder.
When a page is moved or removed, you don't have to do anything with Google:
If you recently changed your site and now have some outdated URLs in the index, Google's crawlers will see this as we recrawl your URLs, and those pages will naturally drop out of our search results.