How to Set Up a Favicon in Next.js
How to change a favicon in Next.js with the App Router or Pages Router, which icon files and sizes to provide, how the metadata API handles icons, and why an old icon keeps showing.
Contents
Most Next.js favicon problems come down to two things: which router the project uses, and which icon file Next.js and the browser end up serving. In the App Router, put icon files with reserved names in the app directory, or declare them through the metadata API. In the Pages Router, put the files in public and reference them with link tags. If the old icon still appears after the change, the usual causes are a leftover default file, a conflicting declaration or a cached copy, so check those in order before editing the artwork. The source material for this article did not include a specific project, Next.js version or icon file. The guidance below therefore covers documented framework behavior and general file-inspection principles, not one particular setup.
Changing the favicon with the App Router
The App Router uses file conventions. A file named favicon.ico at the root of the app directory becomes the site favicon, and Next.js adds the matching tag to the document head automatically. Projects created with the standard starter already contain this file. To change the favicon, replace that file instead of adding a second one somewhere else.
- app/favicon.ico: the classic favicon. It is only recognized at the root of the app directory.
- app/icon.png, icon.svg, icon.jpg or icon.ico: an additional or alternative icon. These files can also sit inside route segments to override the icon for that part of the site.
- app/apple-icon.png or apple-icon.jpg: the icon Apple devices use when someone saves the site to the home screen.
- app/icon.tsx or icon.js: generates an icon in code, usually with ImageResponse, when the icon must be built dynamically.
app/
favicon.ico
icon.svg
apple-icon.png
layout.tsx
page.tsx
For multiple icon files of the same type, the documentation describes a numeric suffix convention such as icon1.png and icon2.png. Check the documentation for your installed version before relying on it.
Declaring icons through the metadata API
Instead of file conventions, you can export a metadata object from the root layout and list icons in its icons field. The paths point to files in the public directory. Use this approach when the icon filenames must stay as they are, or when you want explicit control over type and size attributes.
// app/layout.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
icons: {
icon: [
{ url: '/favicon.ico' },
{ url: '/icon.svg', type: 'image/svg+xml' },
],
apple: '/apple-icon.png',
},
}
Do not use both approaches for the same icon. File-based metadata takes priority over config-based metadata. If app/favicon.ico still exists, it can override the icon you declared in the metadata object, and the change will appear to have no effect.
Changing the favicon with the Pages Router
The Pages Router does not generate icon tags from file names. Put the icon files in the public directory, which is served from the site root. Then add link tags to the head, either in a custom _document or through the Head component in a shared layout.
// 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" sizes="any" />
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
</Head>
<body>
<Main />
<NextScript />
</Body>
</Html>
)
}
Browsers request /favicon.ico by default even without a link tag. A stale public/favicon.ico can therefore keep appearing in some contexts until you replace or remove it.
Which favicon sizes to provide
Next.js does not resize icons for you. It serves the files you supply and describes them in the head, so the files must already cover the sizes browsers and devices need. Common conventions are listed below. Treat them as widely used defaults rather than requirements from this article's source material.
| File | Typical content | Purpose |
| favicon.ico | Several small sizes in one file, commonly 16×16, 32×32 and 48×48 | Browser tabs, bookmarks and legacy requests to /favicon.ico |
| icon.svg | One square vector graphic | Scalable icon in browsers that support SVG favicons |
| icon.png | A larger square raster, for example 192×192 or 512×512 | Fallback and higher-density displays |
| apple-icon.png | 180×180 square, no transparency recommended | Home-screen icon on Apple devices |
Browser support for SVG favicons varies. Keep an ICO or PNG fallback next to the SVG instead of relying on the SVG alone.
Preparing an SVG logo for use as a favicon
An .svg extension, or a preview that looks sharp, does not prove the file is truly vector. Open the file in a text editor or a vector editor and check what it contains. A path-based logo stays crisp at any size. An SVG that wraps an embedded PNG or JPEG only scales that bitmap, so check for an image element or a base64 data string.
- Paths versus embedded raster: look for path, circle or polygon elements, not an image element with base64 data.
- Live text: text elements depend on fonts that are not available when the icon is rendered, so convert lettering to outlines.
- Canvas shape: give the root svg element a square viewBox. A non-square viewBox makes the logo shrink or shift in the tab.
- Detail at small size: fine strokes, thin gaps and small type become unreadable at tab size. This is a visual judgment, not a file property, so check it by viewing the icon at 16 and 32 pixels.
- Color against tab backgrounds: some browsers honor a prefers-color-scheme media query inside the SVG, which lets the icon switch colors for dark themes. Do not depend on it everywhere.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<style>
path { fill: #111; }
@media (prefers-color-scheme: dark) {
path { fill: #fff; }
}
</style>
<path d="..." />
</svg>
In the snippet above, the d attribute is a placeholder for your logo's path data. Having a logo file does not mean you are allowed to use or modify it. Confirm that you have the rights before you simplify, recolor or crop a brand mark for a favicon.
Why the favicon does not change: order of checks
- 1. Find every icon source. In the App Router, look for favicon.ico and icon files in app and its route segments, plus icon entries in the metadata exports. In the Pages Router, look in public and in _document or shared Head components. Remove duplicates you do not intend to keep.
- 2. Check the default starter file. A leftover app/favicon.ico from project creation is a common reason a new icon never appears.
- 3. Inspect the rendered head. View the page source or use developer tools to see which link rel="icon" tags are actually output and which URLs they point to.
- 4. Request the icon URL directly. Open the path from the link tag in the browser to confirm the server returns the new file, not a 404 or the old image.
- 5. Rule out the browser cache. Browsers cache favicons aggressively and sometimes separately from the page. Hard reload, open a private window, or try another browser.
- 6. Restart the dev server. After adding or renaming special files, restart next dev so the new files are picked up.
- 7. Check the deployment layer. On a deployed site, a CDN or hosting cache may still serve the previous file until it is purged or the filename changes.
What could not be confirmed here
No project-specific evidence was provided: no Next.js version, router type, file listing or icon file to inspect. File conventions and metadata options have changed between Next.js releases, so check the documentation for the installed version if anything above does not match what you see. Whether a particular logo is legible at favicon size, or truly vector inside, can only be decided by opening that file. The steps in this article tell you what to look for, but they cannot replace that inspection.