Next.js with Smart CDN & SPR

Hi there, it’s Tom again from team expressFlow! Today I’ll show you how we’re leveraging Vercel’s powerful deployment infrastructure for our company’s main page built using Next.js - the very site you’re currently at. To be more specific, I’ll write about one particular handy caching-mechanism, dubbed Serverless Pre-Rendering as well as the Vercel Edge Network. Let’s jump right in!

SPR

As of lately, you had basically two choices for your site’s deployment: either generate static pages (SSG, “static site generation”) at build time or let your server prerender a page when a visitor visits it (SSR, “server side render”).

And that’s all fine and dandy until we take a look at both strategies’ downsides. For SSG, changes can only be made at build time, which means your CI/CD is the sole responsible for updating the site: Make changes (either in-code or from your headless CMS), trigger a run through a commit and wait until the deployment has finished. For SSR, a busy server (or one that’s completely down, in the worst case) has a large negative impact on the site’s performance. Granted, we can use the Cache-Control-header, but caching on the client side may not always be the best choice.

Using Vercel’s Serverless Pre-Rendering, these shortcomings can be eliminated: every time a user visits a page with SPR enabled, Vercel’s backend checks if a static version of it exists and if it’s max age timeout hasn’t been reached yet. If that’s the case, Vercel serves this purely static page, no server-time needed. If no static version exists yet (e.g. after a new deployment) a serverless function gets invoked, creates a static version of the page, serves it to the user but also keeps it in the Vercel Edge Network, a special CDN built on top of AWS and GCP. And if the current static version is outdated, it still gets served until a new one has been created in the background.

If you’ve used a server for handling incoming requests, the potential risk of a downtime/slow response is practically eliminated. Even if no server responds, there’s a static version available from the CDN. Here’s the code to active this feature for your Vercel-deployment:

// Just an example function. What's important is
// that is accepts a req/res-tuple as input, as 
// we have to set the Cache-Control header on the
// response. Here, we're using a TTl of 12 hours.
export default async function (req: NextApiRequest, res: NextApiResponse) {
  res.setHeader("Cache-Control", `s-maxage=${60 * 60 * 12}, stale-while-revalidate`);
}

For a practical example, we’re using stale-while-revalidate for our RSS-feed. Note that this code uses SSR for demonstration purposes to show that you're not forced to return a view. Yet the same caching-strategy applies if you're defining an API endpoint (as our RSS is actually implemented).

// ... imports ...

interface PageProps {}

// No HTML gets retunred, only an XML
// file defined in 'getServerSideProps'.
export default function RssPage(prpos: PageProps) {
  return null;
}

// Here we're providing 'getServerSideProps'
// according to Vercel's documentation. Note
// that the 'Cache-Control'-header has an age
// of 12 hours. 
export async function getServerSideProps({ res }: GetServerSidePropsContext): Promise<GetStaticPropsResult<PageProps>> {
  if (res && typeof window === "undefined") {
    const posts = await cms.fetch<BlogPostRss[]>(getBlogPostRssQuery());

    res.setHeader("content-type", "application/xml");
    res.setHeader("Cache-Control", `s-maxage=${60 * 60 * 12}, stale-while-revalidate`);
    res.end(generateRss(posts).replace(/&(?!#?[a-z0-9]+;)/, "&amp;"));
  }

  return { props: {} };
}

function generateRss(posts: BlogPostRss[]){
  // ... code ...
}

Difference ISG - SSR

Yet you might be asking: but Tom, didn’t Vercel also announce Incremental Site Generation, dubbed ISG as well as Incremental Static Regeneration (note the "Re")? What’s the difference? Both SSR and ISG/ISR work basically the same way, but with one major difference: SSR serves your pages only after deployment whereas ISG builds the ones you absolutely want to have created at build time. And thanks to ISG, your original set of static sites can theoretically grow indefinitely, as new static pages are created when needed. I’ve linked more detailed documentations from Vercel at this article’s end.

Wrap up

And that’s about it for this post. Vercel currently is a very competitive choice when it comes to both their tight integration with Next.js (a framework built by Vercel) as well as powerful options for leveraging the CDN, dubbed Vercel Edge Network. Yet there’s still a lot more to cover, e.g. using dynamic content in static pages, but that’s for another day and another post. Thanks for the read,

- Tom