Context

Using Next.js as a single-page app (SPA) comes with many benefits but has a major downside: stale sessions. Because users never need to refresh the page, they can go days or weeks without doing so. This makes evolving your API much more difficult. Fully deprecating an endpoint can take weeks or even months.

A common pattern to solve this problem is prompting users to refresh:

To our surprise, there wasn’t a drop-in way to do this in Next.js. They offer some mechanisms to trigger a refresh upon page navigation, but this can be jarring for users without warning. To fill this gap, we’re sharing how we solved this problem.

How It Works

We have the Next.js server track its current version number. Then the front-end track its own version and polls the Next.js server for the latest version number. When these versions differ, prompt the user to refresh.

  1. Version Tracking: The Next.js server tracks the version number and a simple endpoint that compares the request’s version number with the server’s current one
    1. When an engineer wants to prompt users to refresh, they simply increase the LATEST_APP_VERSION version number in a PR
    2. Having the version controlled in code and only deliberately incremented (i.e. not on every deploy) saves users from incessant refresh prompt
      // pages/api/requires-refresh/[version].ts
      
      export const LATEST_APP_VERSION = 105;
      
      export default async function handler(
        req: NextApiRequest,
        res: NextApiResponse<boolean>
      ) {
        const requestVersion = parseInt(req.query.version);
        const needsRefresh = requestVersion < LATEST_APP_VERSION;
        res.status(200).json(needsRefresh);
      }
  2. Refresh Prompt: On the front-end, we get the version on page load, which stays fixed. We then ping the Next.js server every 60 seconds with that version number.
    1. If a version mismatch is detected, meaning the frontend’s version is older than the server’s, display a component that notifies the user to refresh
      import { LATEST_APP_VERSION as versionOnLoad } from "./api/requires-refresh/[version]";
      
      const RefreshChecker = () => {
        const [showRefreshPrompt, setShowRefreshPrompt] = React.useState(false);
      
        React.useEffect(() => {
          async function checkRefresh() {
            const url = "/api/requires-refresh/" + versionOnLoad;
      
            const res = await fetch(url);
            if (res.ok) {
              const needsRefresh = await res.json();
              if (needsRefresh) {
                setShowRefreshPrompt(true);
              }
            }
          }
      
          const id = setInterval(checkRefresh, 60_000);
          return () => clearInterval(id);
        }, []);
      
        if (showRefreshPrompt) {
          // Render your refresh prompt here
          return <div>Refresh required</div>;
        } else {
          return null;
        }
      };
      

Results

This approach works great for allowing engineers to prompt user refreshes when needed by changing a single line of code. It’s simple and works out of the box with Next.js. By sharing our approach, we hope to help other teams who face similar challenges.

At Comulate, we’re building a product-obsessed engineering team. If this and similar challenges sound interesting, we’d love to chat! See open roles here.

Share this post
About the partner
About the partner

Learn how the top 100 brokers automate accounting

Schedule a product demo to see why
Request a demo