Skip to main content
Back to BlogTutorial

How to Add a Favicon in Next.js (App Router & Pages Router)

Step-by-step guide to adding a favicon to a Next.js app, covering the App Router file convention, the Pages Router head approach, and common pitfalls.

August 20267 min read

Next.js handles favicons differently depending on whether you use the App Router (app/) or the Pages Router (pages/). This guide covers both, plus the file conventions that let Next.js generate your <link> tags automatically.

The fastest method: use Next.js file conventions

In the App Router, Next.js auto-detects special filenames in your app/ directory and injects the right tags into <head> with no code.

Place any of these files directly in app/:

FileWhat it does
favicon.icoThe classic .ico — universal fallback
icon.png / icon.svgModern icon; Next.js sizes it automatically
apple-icon.pngiOS / Safari touch icon
app/
├── favicon.ico          # universal fallback
├── icon.png             # main icon (≥512×512)
├── icon.svg             # optional, crisp vector
├── apple-icon.png       # 180×180 for iOS
└── layout.tsx

That's it — no manual <link> tags required. Next.js will emit the correct markup at build time.

Need all those files generated from one image? Upload it to Favicon.one and download the full package ready for the app/ directory.

Adding extra sizes and a manifest

For a complete PWA setup (Android, splash screens, multiple PNG sizes), generate the files and add a metadata-based icon config in layout.tsx:

import type { Metadata } from 'next'

export const metadata: Metadata = {
  icons: {
    icon: [
      { url: '/favicon.ico', sizes: 'any' },
      { url: '/icon.svg', type: 'image/svg+xml' },
      { url: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
      { url: '/favicon-16x16.png', sizes: '16x16', type: 'image/png' },
    ],
    apple: ['/apple-touch-icon.png'],
  },
  manifest: '/site.webmanifest',
}

Pages Router (legacy)

If you're on the Pages Router, there are no auto-detected icon files. Put your files in public/ and add the tags to pages/_document.tsx:

import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html lang="en">
      <Head>
        <link rel="icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
        <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
        <link rel="manifest" href="/site.webmanifest" />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

Common Next.js favicon pitfalls

1. The favicon shows in dev but not in production

Usually a build cache issue. Delete .next and rebuild. Also confirm the file is actually copied to the output — check .next/static or your deployment.

2. Using a non-square image

Favicons must be square. Crop your source image first, or the icon will look stretched. The Favicon.one generator handles cropping and resizing for you.

3. Next.js caching stale favicons

Next.js aggressively hashes static assets. After replacing a favicon, do a hard rebuild and redeploy — and tell users to hard-refresh.

4. Putting favicon files in the wrong folder

App Router: files go in app/. Pages Router: files go in public/. Mixing these up is the most common Next.js favicon mistake.

Verify it worked

After deploying, audit your site with the Favicon Checker — it confirms every required icon and tag is present and correctly referenced.


Want the full favicon file package with the correct Next.js structure? Generate it free at Favicon.one.

Ready to generate your favicon?

Upload your image and get a complete favicon package in seconds. Free, private, and processed right in your browser.