NextJS deploy cannot force 404

Hi there,

I’m having a problem with my NextJS site. For some reason, I cannot force a 404 page to be rendered.

I have a page pages/[...slug].tsx. In it’s getStaticProps function, I do this:

if (isProtected(context)) {
  console.log(`Page "${slug}" is protected`)
  return {
    notFound: true,

console.log(`Page "${slug}" is NOT protected`)

// Normal operations resume here...

Basically, during build time, some environment variable is checked and a notFound: true is returned which forces a 404. During build time in Netlify, I see this in the logs:

2:27:05 PM: info  - Collecting page data...
2:27:07 PM: info  - Generating static pages (0/24)
2:27:09 PM: info  - Generating static pages (6/24)
2:27:09 PM: Page "about" is protected
2:27:09 PM: Page "contact" is protected
2:27:09 PM: info  - Generating static pages (12/24)
2:27:09 PM: Page "" is protected
2:27:09 PM: Page "services/transformation-sprint" is protected
2:27:09 PM: Page "services/design-sprint" is protected
2:27:09 PM: info  - Generating static pages (18/24)
2:27:09 PM: Page "services" is protected
2:27:09 PM: info  - Generating static pages (24/24)
2:27:10 PM: info  - Finalizing page optimization...

This is correct. All of those pages should return a 404 on build time. However, if I visit those url’s on Netlify after the deploy is completed, those pages show up. Locally, this works (running yarn build and yarn start will force the 404 pages).

Looking a bit further into the deploy logs, I find this redirect:

2:27:10 PM:   {
2:27:10 PM:     from: '/:slug/*',
2:27:10 PM:     to: '/.netlify/builders/___netlify-odb-handler',
2:27:10 PM:     status: 200,
2:27:10 PM:     force: false
2:27:10 PM:   },

This does’t seem right to me. This URL should redirect to a 404 page?

Site is located at https://develop–

Hope you can help me.

Kind regards, Niels.

Hey @niels_bankai,

Is there a specific use case that you’re trying to achieve? I’m asking because if you always wish to force a page to 404, why not simply use Netlify Redirects, like:

/about /404.html 404!

But to solve your actual issue, I can see that in your function logs: Netlify App

We’re not seeing that as same as your build during the runtime.

Could you share your isProtected() function? How does that determine what you need exactly?

I am trying to implement my own access control to the site, using an environment variable. This site is driven by a headless CMS (Storyblok), which has a visual preview editor (an iframe which loads the Netlify site and injects data into the NextJS application). So, I need the site to be accessible to users that are logged into the CMS. Regular visitors should not have access to the site. Setting a password in Netlify access control is not an option.

The setup is as following:

Production branch → accessible for both visitors and editors logged into the CMS
Development branch (where the problem is) → unaccessible for visitors, accessible for editors logged into the CMS

The isProtected function looks like this:

export const isProtected = (
  context: GetStaticPropsContext<ParsedUrlQuery, PreviewData>
) => !context.preview && parseBoolean(process.env.PROTECTED)

The context.preview check is NextJS’ preview mode (Advanced Features: Preview Mode | Next.js). The parseBoolean function just converts a string to an actual boolean, nothing special. The PROTECTED env variable is set in netlify.toml:

  PROTECTED = "true"

Hope this helps.

netlify.toml environment variables are not usable during the runtime, they’re only accessible during the build time.

You need to set a variable in the UI.

I can’t do that, because this variable only needs to apply to a single branch. I want the main branch to be fully accessible, so this variable needs to be false for that branch, yet it needs to be true for the develop branch. Since Netlify doesn’t have an option to set separate variables per branch in the UI, this is the only way I can make a distinction between those two branches.

However, your reply did lead me to the solution. NextJS strips variables which are not prefixed with NEXT_PUBLIC_ upon build time. In theory, that shouldn’t matter, since I am calling this isProtected function inside getStaticProps, thus I’m using SSG to create the 404 pages at build time. In practice, this does have an effect. I don’t know why, but if I prefix the env variable with NEXT_PUBLIC_, it does work. I think this has something to do with how Netlify creates NextJS handler functions? Again, I’m not sure, but at least it now works.

Thanks for the help.

Not sure why that flow was needed, but glad to hear you found something that works for you!

This (experimental for a while longer, but we use it in production already and it works well) feature does let you set branch-specific variables that can be used with functions: Get started with scopes and deploy contexts | Netlify Docs

Update: I’ve tried switching to the new environment variables setup in the UI and I no longer have to prefix my ENV variables with NEXT_PUBLIC_. I’ll be sticking to this. Thanks for the help!