NextJS redirect not working for static assets

  • Site name: foodincome.netlify.app

Other similar topics I’ve checked:

Hi, I’ve converted a website to NextJS in one of my environments (specifically: dev--foodincome.netlify.app). Building and deploying works fine, but I’m getting 404 errors on static assets (i.e. /_next/static/whatever). A deploy preview of this in action can be seen here: FoodIn'come

I’ve also checked out the support guide on redirects albeit most of it doesn’t apply to my case (no _redirect file, default config on almost everything). Also as here I have asset optimization disabled.

For reference, here’s my netlify.toml:

[build]

command = "npm run build"

[context.production.environment]
  REACT_APP_BASE_URL = "https://foodincome.herokuapp.com"

[context.dev]
  publish = ".next"

[context.dev.environment]
  NEXT_PUBLIC_BASE_URL = "https://foodincome-dev.herokuapp.com"

[[plugins]]
  package = "@netlify/plugin-nextjs"

Also, my .next.config.js:

/** @type {import('next').NextConfig} */

const nextConfig = {
  reactStrictMode: true,
  compiler: {
    styledComponents: true,
  },
}

module.exports = nextConfig

Relevant package versions:

  • @netlify/plugin-nextjs: ^4.2.7
  • next: ^12.1.0

Is there anything wrong with my config or is it a bug?

As an example, I see a 404 error when trying to access /_next/static/chunks/main-a054bbf31fb90f6a.js.

If there are no redirects in effect, then your build would need to be placing a file in that location for it to be deployed by Netlify and accessible.

Have you checked what your build is outputting?
Have you set your “Publish directory” (Build configuration overview | Netlify Docs) appropriately?

I have unset all settings from the Netlify UI and set everything from netlify.toml.
The published directory is right, the problem is with redirects. The netlify-next plugin does generate redirects for NextJS, but somehow they are not applied correctly (even though they seem fine).

Check out this snippet:

    [[context.dev.redirects]]
    from = "/_next/static/*"
    to = "/static/:splat"
    status = 200

Generated netlify.toml:

[functions]

  [functions._ipx]
  node_bundler = "nft"

  [functions.___netlify-handler]
  included_files = [
    ".env",
    ".env.local",
    ".env.production",
    ".env.production.local",
    ".next/server/**",
    ".next/serverless/**",
    ".next/*.json",
    ".next/BUILD_ID",
    ".next/static/chunks/webpack-middleware*.js",
    "!.next/server/**/*.js.nft.json",
    "!node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*",
    "!node_modules/next/dist/server/lib/squoosh/**/*.wasm",
    "!node_modules/next/dist/next-server/server/lib/squoosh/**/*.wasm",
    "!node_modules/next/dist/compiled/webpack/bundle4.js",
    "!node_modules/next/dist/compiled/webpack/bundle5.js",
    "!node_modules/next/dist/compiled/terser/bundle.min.js",
    "!node_modules/sharp/**/*"
  ]
  external_node_modules = []
  node_bundler = "nft"

  [functions.___netlify-odb-handler]
  included_files = [
    ".env",
    ".env.local",
    ".env.production",
    ".env.production.local",
    ".next/server/**",
    ".next/serverless/**",
    ".next/*.json",
    ".next/BUILD_ID",
    ".next/static/chunks/webpack-middleware*.js",
    "!.next/server/**/*.js.nft.json",
    "!node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*",
    "!node_modules/next/dist/server/lib/squoosh/**/*.wasm",
    "!node_modules/next/dist/next-server/server/lib/squoosh/**/*.wasm",
    "!node_modules/next/dist/compiled/webpack/bundle4.js",
    "!node_modules/next/dist/compiled/webpack/bundle5.js",
    "!node_modules/next/dist/compiled/terser/bundle.min.js",
    "!node_modules/sharp/**/*"
  ]
  external_node_modules = []
  node_bundler = "nft"

[build]
command = "npm run build"

  [build.environment]
  NEXT_PRIVATE_TARGET = "server"

[[plugins]]
package = "@netlify/plugin-nextjs"

[[redirects]]
from = "/*"
to = "/index.html"
status = 200

[[redirects]]
from = "/_next/static/*"
to = "/static/:splat"
status = 200

[[redirects]]
from = "/_next/image*"
to = "/_ipx/w_:width,q_:quality/:url"
status = 301

  [redirects.query]
  url = ":url"
  w = ":width"
  q = ":quality"

[[redirects]]
from = "/_ipx/*"
to = "/.netlify/builders/_ipx"
status = 200

[[redirects]]
from = "/cache/*"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/server/*"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/serverless/*"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/traces"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/routes-manifest.json"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/build-manifest.json"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/prerender-manifest.json"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/react-loadable-manifest.json"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/BUILD_ID"
to = "/404.html"
status = 404
force = true

[[redirects]]
from = "/api"
to = "/.netlify/functions/___netlify-handler"
status = 200

[[redirects]]
from = "/api/*"
to = "/.netlify/functions/___netlify-handler"
status = 200

[[redirects]]
from = "/_redirects"
to = "/_redirects"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/apple-touch-icon-114x114.png"
to = "/apple-touch-icon-114x114.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/apple-touch-icon-120x120.png"
to = "/apple-touch-icon-120x120.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/apple-touch-icon-144x144.png"
to = "/apple-touch-icon-144x144.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/apple-touch-icon-152x152.png"
to = "/apple-touch-icon-152x152.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/apple-touch-icon-57x57.png"
to = "/apple-touch-icon-57x57.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/apple-touch-icon-60x60.png"
to = "/apple-touch-icon-60x60.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/apple-touch-icon-72x72.png"
to = "/apple-touch-icon-72x72.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/apple-touch-icon-76x76.png"
to = "/apple-touch-icon-76x76.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/favicon-128.png"
to = "/favicon-128.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/favicon-16x16.png"
to = "/favicon-16x16.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/favicon-196x196.png"
to = "/favicon-196x196.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/favicon-32x32.png"
to = "/favicon-32x32.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/favicon-96x96.png"
to = "/favicon-96x96.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/favicon.ico"
to = "/favicon.ico"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/manifest.json"
to = "/manifest.json"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/mstile-144x144.png"
to = "/mstile-144x144.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/mstile-150x150.png"
to = "/mstile-150x150.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/mstile-310x150.png"
to = "/mstile-310x150.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/mstile-310x310.png"
to = "/mstile-310x310.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/mstile-70x70.png"
to = "/mstile-70x70.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/robots.txt"
to = "/robots.txt"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/icons/cloche.png"
to = "/icons/cloche.png"
status = 200

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/*"
to = "/.netlify/functions/___netlify-handler"
status = 200
force = true

  [redirects.conditions]
  Cookie = [
    "__prerender_bypass",
    "__next_preview_data"
  ]

[[redirects]]
from = "/_next/data/UEwQ5WZ88jBC8RE-GhqkC/design.json"
to = "/.netlify/functions/___netlify-handler"
status = 200

[[redirects]]
from = "/design"
to = "/.netlify/functions/___netlify-handler"
status = 200

[[redirects]]
from = "/*"
to = "/.netlify/functions/___netlify-handler"
status = 200

[context]

  [context.production]

    [context.production.environment]
    REACT_APP_BASE_URL = "https://foodincome.herokuapp.com"

  [context.dev]
  publish = ".next"

    [context.dev.environment]
    NEXT_PUBLIC_BASE_URL = "https://foodincome-dev.herokuapp.com"
    NEXT_PRIVATE_TARGET = "server"

    [context.dev.functions]

      [context.dev.functions._ipx]
      node_bundler = "nft"

      [context.dev.functions.___netlify-handler]
      included_files = [
        ".env",
        ".env.local",
        ".env.production",
        ".env.production.local",
        ".next/server/**",
        ".next/serverless/**",
        ".next/*.json",
        ".next/BUILD_ID",
        ".next/static/chunks/webpack-middleware*.js",
        "!.next/server/**/*.js.nft.json",
        "!node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*",
        "!node_modules/next/dist/server/lib/squoosh/**/*.wasm",
        "!node_modules/next/dist/next-server/server/lib/squoosh/**/*.wasm",
        "!node_modules/next/dist/compiled/webpack/bundle4.js",
        "!node_modules/next/dist/compiled/webpack/bundle5.js",
        "!node_modules/next/dist/compiled/terser/bundle.min.js",
        "!node_modules/sharp/**/*"
      ]
      external_node_modules = []
      node_bundler = "nft"

      [context.dev.functions.___netlify-odb-handler]
      included_files = [
        ".env",
        ".env.local",
        ".env.production",
        ".env.production.local",
        ".next/server/**",
        ".next/serverless/**",
        ".next/*.json",
        ".next/BUILD_ID",
        ".next/static/chunks/webpack-middleware*.js",
        "!.next/server/**/*.js.nft.json",
        "!node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*",
        "!node_modules/next/dist/server/lib/squoosh/**/*.wasm",
        "!node_modules/next/dist/next-server/server/lib/squoosh/**/*.wasm",
        "!node_modules/next/dist/compiled/webpack/bundle4.js",
        "!node_modules/next/dist/compiled/webpack/bundle5.js",
        "!node_modules/next/dist/compiled/terser/bundle.min.js",
        "!node_modules/sharp/**/*"
      ]
      external_node_modules = []
      node_bundler = "nft"

    [context.dev.build]

      [context.dev.build.environment]
      NEXT_PRIVATE_TARGET = "server"

    [[context.dev.redirects]]
    from = "/_next/static/*"
    to = "/static/:splat"
    status = 200

    [[context.dev.redirects]]
    from = "/_next/image*"
    to = "/_ipx/w_:width,q_:quality/:url"
    status = 301

      [context.dev.redirects.query]
      url = ":url"
      w = ":width"
      q = ":quality"

    [[context.dev.redirects]]
    from = "/_ipx/*"
    to = "/.netlify/builders/_ipx"
    status = 200

    [[context.dev.redirects]]
    from = "/cache/*"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/server/*"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/serverless/*"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/traces"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/routes-manifest.json"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/build-manifest.json"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/prerender-manifest.json"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/react-loadable-manifest.json"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/BUILD_ID"
    to = "/404.html"
    status = 404
    force = true

    [[context.dev.redirects]]
    from = "/api"
    to = "/.netlify/functions/___netlify-handler"
    status = 200

    [[context.dev.redirects]]
    from = "/api/*"
    to = "/.netlify/functions/___netlify-handler"
    status = 200

    [[context.dev.redirects]]
    from = "/_redirects"
    to = "/_redirects"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/apple-touch-icon-114x114.png"
    to = "/apple-touch-icon-114x114.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/apple-touch-icon-120x120.png"
    to = "/apple-touch-icon-120x120.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/apple-touch-icon-144x144.png"
    to = "/apple-touch-icon-144x144.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/apple-touch-icon-152x152.png"
    to = "/apple-touch-icon-152x152.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/apple-touch-icon-57x57.png"
    to = "/apple-touch-icon-57x57.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/apple-touch-icon-60x60.png"
    to = "/apple-touch-icon-60x60.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/apple-touch-icon-72x72.png"
    to = "/apple-touch-icon-72x72.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/apple-touch-icon-76x76.png"
    to = "/apple-touch-icon-76x76.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/favicon-128.png"
    to = "/favicon-128.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/favicon-16x16.png"
    to = "/favicon-16x16.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/favicon-196x196.png"
    to = "/favicon-196x196.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/favicon-32x32.png"
    to = "/favicon-32x32.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/favicon-96x96.png"
    to = "/favicon-96x96.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/favicon.ico"
    to = "/favicon.ico"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/manifest.json"
    to = "/manifest.json"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/mstile-144x144.png"
    to = "/mstile-144x144.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/mstile-150x150.png"
    to = "/mstile-150x150.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/mstile-310x150.png"
    to = "/mstile-310x150.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/mstile-310x310.png"
    to = "/mstile-310x310.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/mstile-70x70.png"
    to = "/mstile-70x70.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/robots.txt"
    to = "/robots.txt"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/icons/cloche.png"
    to = "/icons/cloche.png"
    status = 200

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/*"
    to = "/.netlify/functions/___netlify-handler"
    status = 200
    force = true

      [context.dev.redirects.conditions]
      Cookie = [
        "__prerender_bypass",
        "__next_preview_data"
      ]

    [[context.dev.redirects]]
    from = "/_next/data/UEwQ5WZ88jBC8RE-GhqkC/design.json"
    to = "/.netlify/functions/___netlify-handler"
    status = 200

    [[context.dev.redirects]]
    from = "/design"
    to = "/.netlify/functions/___netlify-handler"
    status = 200

    [[context.dev.redirects]]
    from = "/*"
    to = "/.netlify/functions/___netlify-handler"
    status = 200

Hey there, @giovanniberti :wave:

Thanks so much for reaching out, and welcome to the Netlify Forums.

Could you please try updating to the latest version of the plugin to see if this helps address this issue? You can read more about this here: Releases · netlify/netlify-plugin-nextjs · GitHub

I’ve tried updating to v4.3.0 but it doesn’t seem to solve the problem :frowning:

Deploy preview URL: FoodIn'come

Hi @giovanniberti,

It seems you’ve an invalid redirect rule in place:

https://app.netlify.com/sites/foodincome/deploys/623d9b28e9c29d4940833c85#L385

That’s what’s causing issues.

Is there any way I can delete this rule? I currently don’t have any rule in netlify.toml nor a _redirects file.

Edit: I just found in another folder a _redirects file with that rule, I’ll try deleting it and report back.

Edit 2: that was it, thanks for the support!

1 Like