#Users cannot navigate to URLs on older deployments after a new build is

1 messages · Page 1 of 1 (latest)

dry crystal
#

When they click on links, the page doesn’t load and gets stuck

We don't want to refresh page

  • We do not want to force users to refresh the page with a warning.
  • Old assets (all of them actually) are stored on Cloudflare R2 with their build IDs
  • All assets remain always accessible, even after new builds are released.
hollow roseBOT
#

Hi @dry crystal. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

Based on the knowledge sources, I can see that your issue is related to version skew in Next.js, which occurs when users have an older version of your application open while a new deployment is released.

The Problem

When Next.js detects a mismatch between the client's build ID and the server's build ID, it typically performs a hard navigation (full page reload) to retrieve new assets. According to the Next.js documentation on version skew:

Next.js will automatically mitigate most instances of version skew and automatically reload the application to retrieve new assets when detected. For example, if there is a mismatch in the deploymentId, transitions between pages will perform a hard navigation versus using a prefetched value.

However, several GitHub issues indicate that this behavior can cause problems, particularly with:

Potential Solutions

1. Enable Experimental clientSegmentCache Flag

According to a comment in the Link prefetch issue, enabling the experimental clientSegmentCache flag may help:

{
  experimental: {
    clientSegmentCache: true,
  }
}

2. Enable PPR (Partial Prerendering)

Another comment in the same issue mentions that when PPR is enabled, the navigation issues are resolved.

3. Vercel's Skew Protection

#

If you're deploying on Vercel, they offer Skew Protection which routes client requests to their original deployment, preventing client-side state loss. This feature can be enabled in your project's Advanced settings on Vercel.

Important Limitation

The knowledge sources indicate that completely avoiding page refreshes during version skew is challenging. The version skew documentation explicitly states:

When the application is reloaded, there may be a loss of application state if it's not designed to persist between page navigations.

Since you're self-hosting with Cloudflare R2 and want to avoid forced refreshes, you may need to implement custom logic, but the knowledge sources don't provide a complete solution for this specific scenario without using Vercel's Skew Protection or accepting some form of page reload.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@dry crystal Kapa.ai is still learning and improving, please let me know how I did by reacting below.

dry crystal
#

@hollow rose How can I fix in self-deployed version

hollow roseBOT
#

Let me check the knowledge base for you again. Give me one moment! :books:

#

Based on the knowledge sources, here are the approaches you can take for a self-deployed Next.js application to handle version skew:

1. Generate a Consistent Build ID

Configure a consistent build ID across your deployments using the generateBuildId option in next.config.js. According to the self-hosting documentation:

module.exports = {
  generateBuildId: async () => {
    // This could be anything, using the latest git hash
    return process.env.GIT_HASH
  },
}

This ensures that the same build uses the same ID across multiple containers or deployments.

2. Custom Middleware Solution for Version Detection

A user shared a workaround in the Client cannot recover from version skew issue that uses middleware to detect version mismatches and handle them:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import deploymentId from "./staticId";

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname === "/refresh") {
    return NextResponse.next();
  }

  const clientDeploymentId =
    request.nextUrl.searchParams.get("dpl") ||
    request.headers.get("x-deployment-id");

  if (clientDeploymentId && clientDeploymentId !== deploymentId) {
    const isAction =
      request.method === "POST" && request.headers.has("Next-Action");
    const refreshUrl = new URL("/refresh", request.url);

    if (isAction) {
      const response = NextResponse.next();
      response.headers.set("x-action-redirect", refreshUrl.toString());
      return response;
    } else {
      return NextResponse.redirect(refreshUrl);
    }
  }
}
#

Important caveat: The user notes that "You must set a deploymentId in every build, and to keep the deploymentId in sync from server to client, you should generate it in static in build time."

3. For Server Actions Specifically

If you're using Server Actions, you can maintain consistent action IDs across deployments by setting the NEXT_SERVER_ACTIONS_ENCRYPTION_KEY environment variable. According to a comment in the version skew issue, this essentially opts out of the changing action IDs behavior when self-hosting.

Important Limitation

The knowledge sources indicate that completely avoiding page refreshes during version skew without some form of reload is very difficult in self-hosted scenarios. The version skew documentation states that when version skew is detected, Next.js will perform hard navigation, which results in loss of component state like useState.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: