Skip to content

Favicons in Next.js App Router

Problem: Adding Icons with App Router Metadata

Since Next.js 13.4, the App Router introduced significant changes to how you manage site icons. The legacy head.js file and custom <Head> components are now replaced by the metadata API. Developers often face challenges when:

  1. Icon files don't appear in the final HTML output
  2. Cache issues prevent new icons from loading
  3. File location conflicts (public/ vs app/)
  4. Incorrect icon format usage (.png vs .ico)
  5. Missing support for multiple icon sizes

1. Using File Conventions (Simplest Method)

Next.js automatically detects properly named files in your app/ directory:

bash
app/
  icon.svg      # Main icon
  favicon.ico   # Legacy .ico favicon
  apple-icon.png # iOS Home Screen icon

Supported file conventions:

File TypeSupported FormatsValid Locations
favicon.icoapp/
icon.ico, .jpg, .jpeg, .png, .svgapp/**/*
apple-icon.jpg, .jpeg, .pngapp/**/*

Important

Delete the initial public/favicon.ico file to avoid conflicts

2. Configuring icons Metadata

For more control, define icons in your layout's metadata:

tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My App',
  icons: {
    icon: '/favicon/favicon.ico',
    apple: '/favicon/apple-touch-icon.png',
    shortcut: '/favicon/favicon.ico'
  }
}

Place your icon files in the public/favicon/ directory.

3. Advanced Multi-Icon Configuration

Provide multiple icon sizes for different devices:

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

Icon Preparation

Use tools like favicon.io to generate a complete icon set

Advanced Use Cases

Per-Path Custom Icons

Place icon.* files in route segments to override global icons:

bash
app/
  dashboard/
    icon.svg    # Icon for /dashboard/*

Dynamically Generated Icons

Create programmatically generated icons using API routes:

tsx
import { ImageResponse } from 'next/og'

export const size = { width: 32, height: 32 }
export const contentType = 'image/png'

export default function Icon({ params }) {
  return new ImageResponse(
    <div style={{
      background: 'black',
      color: 'white',
      width: '100%',
      height: '100%',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center'
    }}>
      {params.slug[0].toUpperCase()}
    </div>,
    size
  )
}

This generates icons with the first letter of the route slug.

Troubleshooting Guide

Cache Issues

bash
rm -rf .next  # Clear development cache
npm run build # Force fresh build

Common Errors

  1. Conflict Error:
    Error: A conflicting public file and page file was found for path /favicon.ico
    Solution: Remove duplicate files from either app/ or public/

  2. Missing Icons:
    Solution: Verify:

    • Correct location (app/ or public/)
    • Exact filename (icon.svg, not my-icon.svg)
    • Proper metadata type definitions
  3. iOS Icon Not Showing:
    Solution: Ensure:

    • File placed in app/ as apple-icon.png
    • No <meta name="apple-touch-icon"> in separate manual tags

Conflicting Approaches

Avoid adding manual <link> tags directly in layout components as this bypasses Next.js optimization:

tsx
// app/layout.tsx - DON'T DO THIS
export default function Layout() {
  return (
    <html>
      <head>
        <link rel="icon" href="/path/to/icon" /> {/* Conflicts with metadata */}
      </head>
      ...  
    </html>
  )
}

Best Practices Summary

  1. Default Approach: Place icon.svg / favicon.ico in app/
  2. Multi-Resolution: Use icons metadata with array configuration
  3. Organization: Store all icons in public/favicon folder
  4. File Names: Never modify filenames generated by icon converters
  5. Cache Management: Regularly clear .next during development
  6. Device Support: Always include both SVG and ICO versions

For complex implementations, refer to the official Next.js Metadata Documentation.