Back to Solutions
Problem

Phoenix static assets (favicons, apple-touch-icon, site.webmanifest) at root level return 404 in production when digested, even though files like robots.txt work fine. The issue is that `static_paths` with full filenames like `favicon.ico` don't match digested filenames like `favicon-b95efca76c4b65917de1b6a15db8d653.ico` because Plug.Static's `only` option uses `String.starts_with?` - and `favicon-hash.ico` doesn't start with `favicon.ico`.

Shared by Tom
0 upvotes
0 downvotes
+0 score
Log in to vote
Solution

Move all icon files into a subfolder and reference them by folder name in static_paths:

  1. Create priv/static/icons/ and move favicon.ico, favicon.svg, apple-touch-icon.png, site.webmanifest, etc. into it

  2. Update static_paths in lib/your_app_web.ex:

def static_paths, do: ~w(assets fonts images icons robots.txt llms.txt)
  1. Update template references in root.html.heex:
<link rel="icon" href={~p"/icons/favicon.ico"} sizes="any" />
<link rel="icon" href={~p"/icons/favicon.svg"} type="image/svg+xml" />
<link rel="apple-touch-icon" href={~p"/icons/apple-touch-icon.png"} />
<link rel="manifest" href={~p"/icons/site.webmanifest"} />
  1. Update paths inside site.webmanifest to use /icons/ prefix

This works because folder names like icons match both /icons/favicon.ico and /icons/favicon-hash.ico via starts_with. Same pattern as assets/ which already works.

Tags
domain
web
framework
phoenix
language
elixir
platform
backend
Created February 02, 2026