Roni Axelrad
Roni Axelrad

Reputation: 439

next js 13 Dynamic rendering instead of Static rendering when using headers in fetch?

I'm debating with myself that either I didn't understand next 13 new concepts correctly, or it's really a bug ? I'm not sure, and appreciate someone that knows better to suggest what is going on.

I have a simple page.tsx in my 'app' folder of a new next 13 (latest version).

When I fetch data in that page, with fetch, but without adding any headers, the build (yarn/npm build) ends up showing the page is build statically (during build), but when I add a required header (Authorization), the build shows the page is dynamically rendered (per request).

Is it by design? I can't pass a header to the fetch API and render the page statically ?

This is the code I'm using :

const getData = async () => {
  const res = await fetch(
    "https://endless-app.onrender.com/api/site-settings",
    {
      headers: {
        Authorization: `Bearer 24653f35c767c9d1ed04f15f143eda0ac12b1cd60d`,
      },
    }
  );
  const data = await res.json();
  return data;
};

export default async function About() {
  const data = await getData();


  return (
    <div>
      <h1>About</h1>
    </div>
  );
}  

that ends up as dynamic rendering: enter image description here

Just removing the headers from fetch, ends up static rendering, as I like it to be:

const getData = async () => {
  const res = await fetch(
    "https://endless-app.onrender.com/api/site-settings"
  );
  const data = await res.json();
  return data;
};

enter image description here

Appreciate any help.

Thank you !

Upvotes: 5

Views: 8214

Answers (3)

Asalcedo07
Asalcedo07

Reputation: 11

I don't think what you're trying to achieve is possible with a user token/cookie, it may be possible if the Authorization token itself comes from the external api like in this article using next v12.

Per the current /app v13 docs:

Requests are not cached if: Dynamic methods (next/headers, export const POST, or similar) are used and the fetch is a POST request (or uses Authorization or cookie headers)

.....

Note how dynamic functions always opt the route into dynamic rendering, regardless of whether the data fetching is cached or not. In other words, static rendering is dependent not only on the data fetching behavior, but also on the dynamic functions used in the route.

...

Dynamic functions rely on information that can only be known at request time such as a user's cookies, current requests headers, or the URL's search params.

Upvotes: 1

rudy_0103
rudy_0103

Reputation: 21

static rendering occurs when the data fetching is cached

if request contains Authorization Header the request will not be cached

https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering

https://nextjs.org/docs/app/building-your-application/data-fetching/caching

Upvotes: 2

yun_jay
yun_jay

Reputation: 1180

You can fix that behaviour if you set cache: "force-cache" inside your fetch options.

If you are using another https client api, you can set the following reserved export to force static rendering:

export const revalidate = 'force-cache'

So your code would look like this if you use the fetch api:


const getData = async () => {
  const res = await fetch(
    "https://endless-app.onrender.com/api/site-settings",
    {
      cache: "force-cache",
      headers: {
        Authorization: `Bearer ********************************`,
      },
    }
  );
  const data = await res.json();
  return data;
};

export default async function About() {
  const data = await getData();


  return (
    <div>
      <h1>About</h1>
    </div>
  );
}  

If you are using another http client api like axios, then you have to use the reserved export revalidate and set it to 'force-cache' if they don't provide revalidation option:

import axios from "axios";

const getData = async () => {
  const res = await axios.get("https://jsonplaceholder.typicode.com/posts", {
    headers: {
      Authorization: `Bearer ********************************`,
    },
  });
  return res.data;
};

export default async function About() {
  const data = await getData();

  return (
    <div>
      <h1>About</h1>
    </div>
  );
}

export const revalidate = "force-cache";

Keep in mind that this option does not override the revalidate value set by individual fetch requests. So the second option would not work for the fetch api, since they already implemented a revalidation option with the cache: 'force-cache' property.

This is also documented under the new nextjs 13 beta documentation under Caching and Route Segment Config Options

Upvotes: 5

Related Questions