afaqrashid.com  ·  portfolio · 2026 ed.

Next.js Favicon Not Showing or Updating? 5 Causes I Tested

If your Next.js favicon isn't showing, check five things. The file must be called favicon.ico and sit directly in app/. There can't be a second favicon.ico in public/. metadata.icons doesn't remove the default app/favicon.ico. Your browser may be showing a cached icon. And Google has its own rules before it shows a favicon in search.

I tested each of these on a fresh Next.js 16.4.4 app with next build and next start, and checked the HTML and the file each URL returned. None of them gave a build error or a warning.

1. The file has the wrong name or sits in the wrong folder

Next.js only picks up a favicon in one place. The docs say "The favicon image can only be located in the top level of app/", and it has to be an .ico file. If you use a src folder, that means src/app/.

I tried both of these mistakes:

app/favicon.png          ignored: favicon only accepts .ico
app/(site)/favicon.ico   ignored: a route group isn't the top level of app/

In both cases the page had no icon tag at all, /favicon.ico returned a 404, and the build passed.

The fix is to move the file to app/favicon.ico. If you want a PNG or SVG instead, name it icon.png or icon.svg. The icon convention accepts .ico, .jpg, .jpeg, .png and .svg, and it works in any folder.

2. It works in dev but not in production

This one surprised me. I put a favicon.ico in app/ and a different favicon.ico in public/, then requested /favicon.ico from both servers:

next dev               serves app/favicon.ico
next build && start    serves public/favicon.ico

In both, the tag in the head pointed at /favicon.ico with a query string generated from the app/ file, and its sizes attribute described the app/ file. In production, the image behind that tag was the other one.

So you can see your new icon locally, deploy, and get the old one. Keep one favicon.ico, not two. This finds every copy outside node_modules:

find . -name "favicon.*" -not -path "./node_modules/*" -not -path "./.next/*"

3. metadata.icons doesn't replace the default favicon

create-next-app ships with app/favicon.ico. If you leave it there and set your own icon in the layout, Next.js outputs both:

// app/layout.tsx
export const metadata: Metadata = {
  icons: { icon: "/my-icon.png" },
};
<link rel="icon" href="/favicon.ico?favicon.0hzaxvb3hej93.ico" sizes="48x48" type="image/x-icon"/>
<link rel="icon" href="/my-icon.png"/>

The default icon comes first, and which of the two a browser shows is up to the browser. Delete app/favicon.ico if you set icons in metadata, or replace that file with your own icon and drop the metadata entry.

The same happens with app/icon.png next to app/favicon.ico: you get two icon tags. That's fine if both files are your icon, at different sizes.

4. Your browser is showing an old icon

Browsers keep favicons in their own cache, separate from the page. Next.js helps when the favicon lives in app/: the query string on the link changes when the file changes. In my test, a one-byte change took it from favicon.0hzaxvb3hej93.ico to favicon.3uw818sc71tfn.ico.

Files in public/ that you link by a plain path don't get that. If you changed public/favicon.ico or an icon you set in metadata.icons, open the file's URL directly to confirm the server has the new one. Then check in a fresh browser profile, or give the file a new name.

5. It shows in the browser but not in Google

Google's search results use their own favicon, with their own rules:

  • The link tag has to be on your home page.
  • The icon must be square and at least 8x8px. Google recommends larger than 48x48px.
  • Googlebot-Image must be able to crawl the file, and robots.txt must not block it.
  • The URL should be stable, so don't keep renaming it.
  • After a change, Google says recrawling can take several days to several weeks.

Google accepts icon, shortcut icon, apple-touch-icon and apple-touch-icon-precomposed as the rel value, so the tags Next.js writes are fine. If you block paths in robots.txt, make sure the icon isn't under one of them.

Quick checklist

  • favicon.ico sits directly in app/ or src/app/, and it's an .ico file.
  • There's only one favicon.ico in the project.
  • If you set metadata.icons, the default app/favicon.ico is gone.
  • Opening /favicon.ico on the live site shows the new icon.
  • The home page has the icon tag, and robots.txt doesn't block the file.

My metadata checker below reads a live page's head and shows the tags it finds.

Related

Sources