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

In short, have the Next.js front-end track its version number and poll the Next.js server for what the latest version number is. When they 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;
        }
      };
      

Conclusion

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 our open roles here.

Share this post
About the partner
About the partner

Top broker finance & accounting teams are powered by Comulate

Schedule a product demo to see why
We care about your data in our privacy policy.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.