Favicon ToolsVerifyBuild
Framework

Rails Favicon Generator

Rails expects the favicon to go through the asset pipeline. Put the files under app/assets/images and declare them with favicon_link_tag in the application layout so production fingerprinting keeps working.

Asset pipeline, not public/ alone

Rails 8 defaults to Propshaft. Files under app/assets/images are fingerprinted on precompile and served from /assets/... in production. The favicon_link_tag helper resolves the logical name to that digested path, which is why a bare /favicon.ico in public/ and a helper-managed icon are different strategies.

public/favicon.ico still works as a legacy fallback for clients that request the root path without reading link tags. For the rest of the set (PNG sizes, apple-touch-icon, manifest) use the helpers in the layout so digests stay correct after each deploy.

Where the files go

  • my-rails-app/
    • app/
      • assets/
        • images/
          • favicon.icoadd
          • favicon-32x32.pngadd
          • apple-touch-icon.pngadd180x180
          • icon-192.pngadd
          • icon-512.pngadd
      • views/
        • layouts/
          • application.html.erbhelpers go here
    • public/
      • favicon.icoaddoptional root fallback
      • site.webmanifestadd

Propshaft copies everything under app/assets into public/assets on precompile. The layout should reference logical names, not the digested filenames.

application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title><%= content_for?(:title) ? yield(:title) : "My app" %></title>
    <meta name="viewport" content="width=device-width,initial-scale=1">

    <%= favicon_link_tag "favicon.ico" %>
    <%= favicon_link_tag "favicon-32x32.png", rel: "icon", type: "image/png", sizes: "32x32" %>
    <%= favicon_link_tag "apple-touch-icon.png", rel: "apple-touch-icon", type: "image/png" %>
    <link rel="manifest" href="/site.webmanifest">

    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

Pass type: and rel: for anything that is not a classic .ico. The helper defaults to rel=icon and type=image/x-icon, which is wrong for PNG and SVG.

Check the small end first

Example favicon at 16 by 16 pixels
16px
Example favicon at 32 by 32 pixels
32px
Example favicon at 48 by 48 pixels
48px
Example favicon at 96 by 96 pixels
96px
Example favicon at 180 by 180 pixels
180px
Rendered at true pixel dimensions. A mark that survives 16px survives the tab; one that only reads at 180px will not.

Rails favicon FAQ

Propshaft or Sprockets: does the helper change?

favicon_link_tag is the same. Propshaft is the Rails 8 default and serves logical paths from app/assets without a Sprockets manifest. If you still run Sprockets, keep the files under app/assets/images and keep using the helper.

Why put a copy in public/ as well?

Some clients request /favicon.ico before they parse link tags. A small root copy covers that case. The layout helpers still own the full set that modern browsers and iOS actually use.

The icon did not update after deploy.

Confirm assets:precompile ran and the layout is using favicon_link_tag so the href changed with the digest. If you only replaced a file in public/ with the same name, browsers may keep the old cached icon until the URL changes or a private window is used.

Related platforms