Slik legger du til favicon i Next.js-prosjektet ditt: Komplett implementeringsguide for 2025

Favicon.im

Favicons er avgjørende for moderne webapplikasjoner — de vises i nettleserfaner, bokmerker, mobile hjemmeskjermer og PWA-installasjoner. Next.js tilbyr flere implementeringsmetoder avhengig av ruterkonfigurasjonen og funksjonskravene dine.

Denne omfattende guiden gir deg alt du trenger for å implementere profesjonelle favicon-systemer i Next.js-prosjekter, fra grunnleggende oppsett til avanserte dynamiske funksjoner.

Hva du vil lære:

  • Next.js 13+ App Router favicon-implementering
  • Eldre Pages Router-kompatibilitetsmetoder
  • Dynamiske favicon-oppdateringer og tematilpasning
  • PWA- og flerenhetsoptimalisering
  • Ytelsesoptimalisering og feilsøking
  • Praktiske kodeeksempler og beste praksis

Hurtigstart: Grunnleggende favicon-oppsett (5 minutter)

Steg 1: Generer favicon-filene dine

Anbefalt verktøy: Bruk RealFaviconGenerator eller Favicon.io for profesjonelle resultater.

Anbefalt filstruktur:

public/
├── favicon.ico          # Universell kompatibilitet (16x16, 32x32)
├── favicon-16x16.png   # Nettleserfaner (eldre støtte)
├── favicon-32x32.png   # Høyoppløselige nettleserfaner
├── apple-touch-icon.png # 180x180 (iOS-hjemmeskjerm)
├── android-chrome-192x192.png # Android-hjemmeskjerm
├── android-chrome-512x512.png # PWA og høyoppløselige skjermer
└── site.webmanifest    # Progressive Web App-manifest

Steg 2: Umiddelbart grunnleggende oppsett

Nullkonfigurasjonsmetode: Plasser favicon.ico i public-katalogen. Next.js serverer den automatisk på /favicon.ico.

Rask verifisering: Besøk http://localhost:3000/favicon.ico for å bekrefte at filen er tilgjengelig.

Next.js 13+ App Router-implementering

Metode 1: Metadata API-konfigurasjon (anbefalt)

Hvorfor denne metoden: Typesikker, innebygd Next.js-støtte, automatisk optimalisering, bedre SEO.

Next.js App Router støtter filbasert favicon-konfigurasjon:

// app/layout.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My Next.js App',
  description: 'Amazing Next.js application',
  icons: {
    icon: '/favicon.ico',
    shortcut: '/favicon-16x16.png',
    apple: '/apple-touch-icon.png',
  },
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

Metode 2: Profesjonell flerenhetskonfigurasjon

For produksjonsklare applikasjoner med omfattende plattformstøtte:

// app/layout.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My Next.js App',
  description: 'Amazing Next.js application',

  // Omfattende favicon-konfigurasjon
  icons: {
    // Primære nettleserikoner
    icon: [
      { url: '/favicon-16x16.png', sizes: '16x16', type: 'image/png' },
      { url: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
    ],

    // Eldre ICO-støtte
    shortcut: '/favicon.ico',

    // iOS-hjemmeskjermikoner
    apple: [
      { url: '/apple-touch-icon.png', sizes: '180x180', type: 'image/png' },
    ],

    // Android- og PWA-ikoner
    other: [
      {
        rel: 'icon',
        url: '/android-chrome-192x192.png',
        sizes: '192x192',
        type: 'image/png'
      },
      {
        rel: 'icon',
        url: '/android-chrome-512x512.png',
        sizes: '512x512',
        type: 'image/png'
      },
    ],
  },

  // PWA-manifest for app-lignende opplevelse
  manifest: '/site.webmanifest',

  // Ekstra mobiloptimalisering
  other: {
    'theme-color': '#000000',
    'msapplication-TileColor': '#000000',
  }
}

Metode 3: Dynamisk favicon-generering

Avansert brukstilfelle: Dynamiske favicons basert på brukerkontekst, miljø eller applikasjonstilstand.

// app/layout.tsx
import { headers } from 'next/headers'
import type { Metadata } from 'next'

export async function generateMetadata(): Promise<Metadata> {
  const headersList = headers()
  const userAgent = headersList.get('user-agent') || ''

  // Miljøbasert favicon-valg
  const isDevelopment = process.env.NODE_ENV === 'development'
  const isMobile = /Mobile|Android|iPhone/i.test(userAgent)

  // Dynamisk favicon-logikk
  let faviconPath = '/favicon.ico'
  if (isDevelopment) {
    faviconPath = '/favicon-dev.ico' // Utviklingsindikator
  } else if (isMobile) {
    faviconPath = '/favicon-mobile.ico' // Mobiloptimalisert versjon
  }

  return {
    title: 'My Next.js App',
    icons: {
      icon: faviconPath,
      apple: '/apple-touch-icon.png',
    },
    // Ekstra dynamisk metadata
    other: {
      'theme-color': isDevelopment ? '#ff6b6b' : '#000000',
    }
  }
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

Eldre Pages Router-implementering (Next.js 12 og lavere)

Metode 1: Komponentnivå-implementering med next/head

Best for: Sidespesifikke favicons eller når du trenger ulike favicons for ulike ruter.

// pages/_app.tsx
import Head from 'next/head'
import type { AppProps } from 'next/app'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Head>
        <link rel="icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
        <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
        <link rel="manifest" href="/site.webmanifest" />
        <meta name="theme-color" content="#000000" />
      </Head>
      <Component {...pageProps} />
    </>
  )
}

Metode 2: Global implementering med Custom Document (anbefalt)

Best for: Applikasjonsomfattende favicon-konfigurasjon som gjelder for alle sider.

// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html lang="en">
      <Head>
        {/* Essensielle nettleserikoner */}
        <link rel="icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />

        {/* Mobilenhetikoner */}
        <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
        <link rel="icon" type="image/png" sizes="192x192" href="/android-chrome-192x192.png" />
        <link rel="icon" type="image/png" sizes="512x512" href="/android-chrome-512x512.png" />

        {/* PWA- og plattformkonfigurasjon */}
        <link rel="manifest" href="/site.webmanifest" />
        <meta name="theme-color" content="#000000" />
        <meta name="msapplication-TileColor" content="#000000" />
        <meta name="msapplication-config" content="/browserconfig.xml" />

        {/* Ekstra SEO- og mobiloptimalisering */}
        <meta name="apple-mobile-web-app-capable" content="yes" />
        <meta name="apple-mobile-web-app-status-bar-style" content="default" />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

Avanserte implementeringer

Dynamiske favicon-oppdateringer

Opprett en tilpasset hook for dynamiske favicon-oppdateringer:

// hooks/useFavicon.ts
import { useEffect } from 'react'

export const useFavicon = (faviconUrl: string) => {
  useEffect(() => {
    const link = document.querySelector("link[rel*='icon']") as HTMLLinkElement ||
                 document.createElement('link')

    link.type = 'image/x-icon'
    link.rel = 'shortcut icon'
    link.href = faviconUrl

    if (!document.querySelector("link[rel*='icon']")) {
      document.getElementsByTagName('head')[0].appendChild(link)
    }
  }, [faviconUrl])
}

// Bruk i komponent
export default function MyComponent() {
  const [theme, setTheme] = useState('light')

  useFavicon(theme === 'dark' ? '/favicon-dark.ico' : '/favicon-light.ico')

  return (
    <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
      Toggle Theme
    </button>
  )
}

Varslingsmerke-favicon

Opprett et varslingssystem med favicon-merker:

// components/NotificationFavicon.tsx
import { useEffect, useRef } from 'react'

interface NotificationFaviconProps {
  count: number
  originalFavicon?: string
}

export const NotificationFavicon: React.FC<NotificationFaviconProps> = ({
  count,
  originalFavicon = '/favicon-32x32.png'
}) => {
  const canvasRef = useRef<HTMLCanvasElement>(null)

  useEffect(() => {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    canvas.width = 32
    canvas.height = 32

    const img = new Image()
    img.onload = () => {
      if (!ctx) return

      // Tegn originalt favicon
      ctx.drawImage(img, 0, 0, 32, 32)

      if (count > 0) {
        // Tegn varslingsmerke
        ctx.fillStyle = '#ff4444'
        ctx.beginPath()
        ctx.arc(24, 8, 8, 0, 2 * Math.PI)
        ctx.fill()

        // Tegn antall-tekst
        ctx.fillStyle = 'white'
        ctx.font = 'bold 10px Arial'
        ctx.textAlign = 'center'
        ctx.textBaseline = 'middle'
        ctx.fillText(count > 9 ? '9+' : count.toString(), 24, 8)
      }

      // Oppdater favicon
      const link = document.querySelector("link[rel*='icon']") as HTMLLinkElement ||
                   document.createElement('link')
      link.type = 'image/png'
      link.rel = 'shortcut icon'
      link.href = canvas.toDataURL()

      if (!document.querySelector("link[rel*='icon']")) {
        document.getElementsByTagName('head')[0].appendChild(link)
      }
    }

    img.src = originalFavicon
  }, [count, originalFavicon])

  return null
}

// Bruk
export default function App() {
  const [notifications, setNotifications] = useState(0)

  return (
    <>
      <NotificationFavicon count={notifications} />
      <button onClick={() => setNotifications(notifications + 1)}>
        Add Notification ({notifications})
      </button>
    </>
  )
}

Tematilpasset favicon

Implementer favicon som tilpasser seg systemtemaet:

// components/ThemeAdaptiveFavicon.tsx
import { useEffect, useState } from 'react'

export const ThemeAdaptiveFavicon = () => {
  const [isDark, setIsDark] = useState(false)

  useEffect(() => {
    // Sjekk systempreferanse
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
    setIsDark(mediaQuery.matches)

    // Lytt etter endringer
    const handleChange = (e: MediaQueryListEvent) => {
      setIsDark(e.matches)
    }

    mediaQuery.addEventListener('change', handleChange)
    return () => mediaQuery.removeEventListener('change', handleChange)
  }, [])

  useEffect(() => {
    const faviconUrl = isDark ? '/favicon-dark.ico' : '/favicon-light.ico'

    const link = document.querySelector("link[rel*='icon']") as HTMLLinkElement ||
                 document.createElement('link')

    link.type = 'image/x-icon'
    link.rel = 'shortcut icon'
    link.href = faviconUrl

    if (!document.querySelector("link[rel*='icon']")) {
      document.getElementsByTagName('head')[0].appendChild(link)
    }
  }, [isDark])

  return null
}

// Bruk i _app.tsx eller layout.tsx
export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <ThemeAdaptiveFavicon />
      <Component {...pageProps} />
    </>
  )
}

Web Manifest-konfigurasjon

Opprett et komplett web-manifest for PWA-støtte:

// public/site.webmanifest
{
  "name": "My Next.js App",
  "short_name": "NextApp",
  "description": "Amazing Next.js application",
  "icons": [
    {
      "src": "/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/android-chrome-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "theme_color": "#000000",
  "background_color": "#ffffff",
  "display": "standalone",
  "start_url": "/",
  "scope": "/"
}

Favicon-generering ved byggetidspunkt

Automatiser favicon-generering under bygging:

// scripts/generate-favicons.js
const sharp = require('sharp')
const fs = require('fs')

const sizes = [
  { size: 16, name: 'favicon-16x16.png' },
  { size: 32, name: 'favicon-32x32.png' },
  { size: 180, name: 'apple-touch-icon.png' },
  { size: 192, name: 'android-chrome-192x192.png' },
  { size: 512, name: 'android-chrome-512x512.png' }
]

async function generateFavicons() {
  const inputFile = 'assets/logo.png'

  for (const { size, name } of sizes) {
    await sharp(inputFile)
      .resize(size, size)
      .png()
      .toFile(`public/${name}`)

    console.log(`Generated ${name}`)
  }

  // Generer ICO-fil
  await sharp(inputFile)
    .resize(32, 32)
    .toFile('public/favicon.ico')

  console.log('Generated favicon.ico')
}

generateFavicons().catch(console.error)
// package.json
{
  "scripts": {
    "generate-favicons": "node scripts/generate-favicons.js",
    "build": "npm run generate-favicons && next build"
  }
}

Vanlige problemer og løsninger

Problem 1: Favicon oppdateres ikke under utvikling

Problem: Nettleseren mellomlagrer gammelt favicon under utvikling

Løsning:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  async headers() {
    return [
      {
        source: '/favicon.ico',
        headers: [
          {
            key: 'Cache-Control',
            value: process.env.NODE_ENV === 'development'
              ? 'no-cache, no-store, must-revalidate'
              : 'public, max-age=31536000, immutable',
          },
        ],
      },
    ]
  },
}

module.exports = nextConfig

Problem 2: Favicon mangler i produksjon

Problem: Statiske filer serveres ikke riktig

Løsning:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        source: '/favicon.ico',
        destination: '/favicon.ico',
      },
    ]
  },
}

module.exports = nextConfig

Problem 3: Flere favicon-formater lastes ikke

Problem: Komplekst favicon-oppsett forårsaker konflikter

Løsning: Bruk en prioritetsbasert tilnærming:

// components/FaviconManager.tsx
import Head from 'next/head'

export const FaviconManager = () => {
  return (
    <Head>
      {/* Høy prioritet: Moderne nettlesere */}
      <link rel="icon" type="image/svg+xml" href="/favicon.svg" />

      {/* Middels prioritet: PNG-reserveløsning */}
      <link rel="icon" type="image/png" href="/favicon-32x32.png" />

      {/* Lav prioritet: Eldre ICO */}
      <link rel="shortcut icon" href="/favicon.ico" />

      {/* Mobilspesifikt */}
      <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
      <link rel="manifest" href="/site.webmanifest" />
    </Head>
  )
}

Testing av favicon-implementeringen din

Sjekkliste for utviklingstesting

  • [ ] Favicon vises i nettleserfaner
  • [ ] Favicon vises i bokmerker
  • [ ] Mobil «Legg til på hjemmeskjerm» fungerer
  • [ ] PWA-installasjonsikon er korrekt
  • [ ] Tilpasning til mørk/lys modus (hvis implementert)

Profesjonelle testverktøy

1. Favicon.im - Umiddelbar validering

  • Rask favicon-utpakking og testing
  • Kompatibilitetssjekk på tvers av plattformer
  • Identifisering av manglende størrelser
  • Best for: Rask validering og feilsøking

2. RealFaviconGenerator Checker - Omfattende analyse

  • Detaljert plattformspesifikk testing
  • PWA-samsvarsverifisering
  • Ytelsesanbefalinger
  • Best for: Profesjonelle revisjoner og optimalisering

3. Browser DevTools - Teknisk feilsøking

  • Nettverksfanen for lastingsproblemer
  • Konsollefeil for manglende filer
  • Applikasjonsfanen for manifest-inspeksjon
  • Best for: Teknisk feilsøking og ytelsesanalyse

Manuelle teststeg

  1. Tøm nettleserbufferen
  2. Besøk nettstedet ditt i inkognitomodus
  3. Test på ulike enheter
  4. Verifiser bokmerkeutseende
  5. Test «Legg til på hjemmeskjerm»-funksjonaliteten

Ytelsesoptimalisering

Filstørrelsesoptimalisering

# Optimaliser PNG-filer
pngquant --quality=65-80 --output favicon-optimized.png favicon.png

# Optimaliser ICO-filer
convert favicon.png -resize 32x32 -colors 256 favicon.ico

HTTP-bufringshoder

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  async headers() {
    return [
      {
        source: '/:path(favicon.ico|.*\\.png)',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, immutable',
          },
        ],
      },
    ]
  },
}

module.exports = nextConfig

Komplett implementeringssjekkliste

Fase 1: Grunnleggende oppsett

  • [ ] Generer favicon-filer ved hjelp av RealFaviconGenerator eller Favicon.io
  • [ ] Plasser filer i public-katalogen med korrekt navngivning
  • [ ] Velg implementeringsmetode (App Router vs Pages Router)
  • [ ] Grunnleggende HTML-oppsett med essensielle link-tagger
  • [ ] Test grunnleggende funksjonalitet på tvers av store nettlesere

Fase 2: Flerenhetsoptimalisering

  • [ ] iOS-hjemmeskjermstøtte (180x180 apple-touch-icon)
  • [ ] Android-kompatibilitet (192x192 og 512x512 ikoner)
  • [ ] PWA-manifestkonfigurasjon for app-lignende opplevelse
  • [ ] Windows-flisstøtte med riktige meta-tagger
  • [ ] Temafarge-integrasjon for mobile nettlesere

Fase 3: Avanserte funksjoner (valgfritt)

  • [ ] Dynamiske favicon-oppdateringer med tilpassede hooks
  • [ ] Tematilpassede ikoner for lys/mørk modus
  • [ ] Varslingsmerker for sanntidsoppdateringer
  • [ ] Ytelsesoptimalisering med bufringshoder
  • [ ] Byggetidsgenerering med automatiserte skript

Viktige implementeringsstrategier

For moderne Next.js-prosjekter (13+)

Anbefalt: Bruk App Router med metadata.icons API for typesikker, optimalisert favicon-håndtering.

For eldre prosjekter (12 og lavere)

Anbefalt: Implementer i _document.tsx for global dekning med next/head for sidespesifikke behov.

For dynamiske applikasjoner

Avansert: Kombiner statisk oppsett med kjøretidsoppdateringer ved hjelp av tilpassede hooks og canvas-manipulering.

For PWA-applikasjoner

Essensielt: Inkluder omfattende manifestkonfigurasjon med flere ikonstørrelser og riktige meta-tagger.

Endelige anbefalinger

Start enkelt: Begynn med grunnleggende ICO + PNG-oppsett, og utvid basert på behov

Bruk profesjonelle verktøy: RealFaviconGenerator for omfattende dekning

Test grundig: Valider på tvers av nettlesere, enheter, og bruk Favicon.im for rask testing

Optimaliser ytelse: Implementer riktige bufringshoder og komprimer favicon-filer

Planlegg for vekst: Design favicon-systemet ditt for å kunne håndtere fremtidige funksjoner som varsler og tematilpasning

Ved å følge denne omfattende guiden vil du skape et profesjonelt favicon-system som forbedrer brukeropplevelsen, styrker merkevaregjenkjenning og fungerer sømløst på alle moderne enheter og nettlesere.

Check Your Favicon

Use favicon.im to quickly check if your favicon is configured correctly. Our free tool ensures your website's favicon displays properly across all browsers and devices.

Free Public Service

Favicon.im is a completely free public service trusted by developers worldwide.

15M+
Monthly Favicon Requests
100%
Free Forever