---
title: Remix Favicon Generator
description: Remix and React Router framework mode declare icons from a root route links() export. Where files go in public/, and how Links renders them.
canonical: https://favicontools.com/platforms/remix-favicon
---

# Remix Favicon Generator

Remix (and React Router framework mode, which is the same route API under renamed packages) does not pick up icons from a special filename. You put files in public/ and return them from the root route's links() export so <Links /> can render them into the document head.

## public/ plus a root links() export

Anything under public/ is copied to the client build root, so public/favicon.ico is served at /favicon.ico. That alone is not enough for a complete set: browsers still need link tags for PNG sizes, the apple-touch-icon, and a manifest, and those tags come from route modules rather than from a static HTML file.

The root route is the right place. Its links() return value is aggregated with every other matched route and rendered by <Links /> in the document shell, so a declaration there covers every page including error boundaries that still render inside the root layout.

## Remix v2 vs React Router framework mode

### React Router (current) (recommended)
Framework mode, new apps
- Packages are react-router and @react-router/*
- Same links() / <Links /> API as Remix v2
- public/ still holds stable static filenames
- Root route file is usually app/root.tsx

### Remix v2
Existing apps
- Packages are @remix-run/*
- Upgrade path is mostly import renames once future flags are on
- app/root.tsx and public/ layout are the same idea
- Icon setup does not change when you rename packages

## Where the files go

```
my-remix-app/
  public/  # copied to the client build root
    favicon.ico  <- add
    favicon-32x32.png  <- add
    apple-touch-icon.png  <- add  # 180x180
    icon-192.png  <- add
    icon-512.png  <- add
    site.webmanifest  <- add
  app/
    root.tsx  # links() lives here
    routes/
```

Same layout whether the package.json still says remix or already says react-router.

## app/root.tsx

```tsx
import { Links, Meta, Outlet, Scripts } from "react-router";
// Remix v2: import those from "@remix-run/react" instead.

export function links() {
  return [
    { rel: "icon", href: "/favicon.ico", sizes: "any" },
    {
      rel: "icon",
      type: "image/png",
      sizes: "32x32",
      href: "/favicon-32x32.png",
    },
    { rel: "apple-touch-icon", href: "/apple-touch-icon.png" },
    { rel: "manifest", href: "/site.webmanifest" },
  ];
}

export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <Outlet />
        <Scripts />
      </body>
    </html>
  );
}
```

Paths are root-absolute against public/. Dropping <Links /> from the shell silently drops every route's link declarations, including the favicon.

> **Put icons on the root route, not a leaf:** A links() export on a nested route only applies while that route is matched. The favicon should outlive every navigation, so it belongs on the root. Leaf routes can still add page-specific preload or stylesheet links without touching the icons.

## Design for the smallest size first

- 16x16
- 32x32
- 48x48
- 96x96
- 180x180

Rendered at true pixel dimensions. The 16px swatch is the one that decides whether a mark works as a favicon.

## Remix favicon FAQ

### Can I put the tags in a raw HTML file instead?

Framework mode apps do not ship a hand-edited index.html the way a Vite SPA does. The document shell is the root route component. If the tags are missing from links() or <Links /> is missing from the shell, they will not appear in the served HTML.

### Should icons go through the Vite import graph?

No. Importing an image from app/ fingerprints the filename, which breaks every fixed href and every browser request for /favicon.ico. Keep icons in public/ so the path stays stable.

### I upgraded from Remix to React Router and the icons vanished.

Check that root.tsx still exports links() and still renders <Links /> after the import rename. The public/ files do not move. A missing <Links /> in the new root shell is the usual cause.
