Contents
  1. Short answer
  2. Where the favicon files belong
  3. Adding the link tags in Twig
  4. Checking the SVG file before using it
  5. If the favicon doesn't appear: order of checks
  6. What this guide cannot confirm

In Symfony, a favicon is a static file plus a few link tags in your base Twig template. Symfony has no favicon setting of its own. The work is putting the right files where the web server can serve them, referencing them correctly, and making sure an SVG icon is actually built as vector shapes.

Short answer

Place the icon files in the project's public directory, or in the assets directory if the project uses AssetMapper. Reference them in base.html.twig with the asset() function. Keep an ICO or PNG fallback next to the SVG version. If the icon still doesn't show, check in this order: the file is reachable, the link tags are in the rendered HTML, the SVG is served with the correct content type, and the browser isn't showing a cached old icon.

Where the favicon files belong

In current Symfony project structures, the public directory is the web root. Files placed there are usually served directly by the web server without passing through Symfony. Many browsers request favicon.ico from the site root even when no link tag exists. Keeping a favicon.ico in public covers that default request.

If the project uses AssetMapper, you can store the icons under assets and reference them through asset(). The output then gets versioned file names, which helps with cache busting. In production, assets must be compiled with the asset-map:compile command, or the versioned paths will not resolve. The automatic root request for favicon.ico is not versioned, so keep a plain copy in public as well. With Webpack Encore, the equivalent is copying the icon files into the build output with copyFiles and referencing them through asset().

Add the tags to the head of templates/base.html.twig, or to a dedicated block that child templates can extend. The asset() function comes from the symfony/asset package. It is normally present in full-stack projects; install it if it is missing.

{% block favicon %}
    <link rel="icon" href="{{ asset('favicon.ico') }}" sizes="any">
    <link rel="icon" href="{{ asset('favicon.svg') }}" type="image/svg+xml">
    <link rel="apple-touch-icon" href="{{ asset('apple-touch-icon.png') }}">
{% endblock %}

Depending on the recipe version, the generated base.html.twig may already include a placeholder icon link. Remove or replace it so it doesn't compete with your own tags. If a child template overrides the head or favicon block, it must call parent() inside that block, or the tags will disappear on those pages. The apple-touch-icon should be a PNG, because that context does not rely on SVG.

Checking the SVG file before using it

A .svg extension or a sharp preview does not prove that an icon is vector-built. An SVG can wrap an embedded bitmap or rely on live text. Both behave differently from true paths when the icon is scaled down to tab size. These are observable file properties, and you can check them directly in the file's markup:

Property | How to check | Why it matters for a favicon
Vector paths | path, circle, rect or polygon elements make up the mark | Scales cleanly at any size
Live text | text elements are present | Renders with whatever fonts the device has, so the letterforms may change; convert text to outlines
Embedded raster | image elements or base64 data inside the file | Scales as a bitmap and can blur, despite the .svg extension
viewBox | A square viewBox is declared on the root element | A missing or non-square viewBox can crop or distort the icon
External references | Links to outside fonts, stylesheets or images | May not load when the file is used as an icon
# Count elements that indicate live text or embedded raster content
grep -c "<text" public/favicon.svg
grep -c "<image" public/favicon.svg
grep -c "base64" public/favicon.svg

# Confirm the viewBox declaration
grep -o 'viewBox="[^"]*"' public/favicon.svg

# With AssetMapper, confirm the icon is mapped
php bin/console debug:asset-map

Whether the icon reads well at small sizes is a visual judgment, not a file property. A full logo with fine detail or a wordmark often becomes illegible in a browser tab, and a simplified mark usually works better. Test it by viewing the icon in an actual tab, on both light and dark browser themes. Some browsers honor a prefers-color-scheme media query inside an SVG favicon for dark-mode variants, but support varies, so verify the behavior in the browsers you target.

Having access to a logo file does not grant permission to use it as a favicon or to modify it, for example by simplifying or recoloring it. Confirm usage rights with the logo owner when the mark isn't your own.

If the favicon doesn't appear: order of checks

  • Open the icon file directly in the browser. A 404 points to a wrong location or path, such as a file outside public or an AssetMapper path that isn't mapped.
  • View the page source and confirm the link tags are present. If they are missing on some pages, a child template is probably overriding the block without calling parent().
  • Check the response headers for the SVG. It should be served as image/svg+xml; a wrong content type from the web server can stop the browser from using it.
  • Rule out caching. Browsers cache favicons persistently, so test in a private window, clear the site data, or change the file name or version.
  • Compare dev and production. In production, confirm the asset map has been compiled and the Symfony cache cleared after changes.
  • Confirm the fallback works. If a browser ignores the SVG, the ICO or PNG version should still appear.

What this guide cannot confirm

No details were available about your Symfony version, front-end setup (AssetMapper, Webpack Encore or neither), web server or hosting configuration. The exact file locations and commands may differ from the defaults described here. Browser support for SVG favicons and dark-mode variants also changes over time, so check current compatibility information before you drop the ICO or PNG fallback.