---
title: React Favicon Generator
description: React has no head management of its own, so favicon links live in index.html. Where that file sits differs between Create React App and Vite.
canonical: https://favicontools.com/platforms/react-favicon
---

# React Favicon Generator

React never touches the document head. Your icon links go in the HTML shell, and which file that is depends on whether the project was scaffolded with Create React App or with Vite.

## Which file owns the head

React renders into a DOM node. Everything above that node (the doctype, the head, the icon links) comes from a static HTML file the bundler processes, and React never rewrites it. So the favicon is a build concern, not a component concern.

Create React App keeps that file at public/index.html, next to the icons themselves. Vite keeps it at the project root as index.html and treats it as the build entry point, with public/ holding the assets. The link tags are the same either way; only the path and the way you write URLs change.

## Create React App vs Vite

### Vite (recommended)
create-vite, and most new React projects
- index.html sits at the project root and is the build entry point
- public/ is copied to the output root untouched
- Reference icons with a root-absolute path: /favicon.ico
- Deploying under a sub-path means setting base in vite.config.js

### Create React App
react-scripts
- The template is public/index.html, alongside the icon files
- URLs must go through the %PUBLIC_URL% placeholder
- The homepage field in package.json controls the deployed path
- CRA is no longer the recommended way to start a React app

## Where the files go

```
my-react-app/
  index.html  # Vite: the link tags go here
  public/
    favicon.ico  <- add  # tabs, legacy
    favicon-32x32.png  <- add
    favicon-16x16.png  <- add
    apple-touch-icon.png  <- add  # 180x180, iOS
    manifest.json  <- add  # PWA metadata
  src/
    App.jsx
    main.jsx
  package.json
```

Vite layout. Create React App has no root index.html: the template lives inside public/ next to the icons, and everything else is the same.

## The link tags

```html
<!-- index.html (Vite) -->
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="manifest" href="/manifest.json" />
```

In Create React App the same tags go in public/index.html, with every href written as %PUBLIC_URL%/favicon.ico and so on.

> **Don't drop the %PUBLIC_URL% prefix:** A bare /favicon.ico in public/index.html works in development and then 404s the moment the app is served from anywhere other than the domain root. The placeholder is what CRA substitutes with the correct base path at build time.

## React favicon FAQ

### Do I need to import the favicon in my React code?

No. Files in public/ are copied to the build output as-is and are not part of the module graph. Importing an image from src/ is the opposite behaviour: the bundler hashes the filename, so the file is no longer reachable at a fixed path like /favicon.ico.

### Why did my favicon 404 after deploying to a sub-path?

The href resolved against the domain root instead of your subdirectory. In Vite, set base in vite.config.js. In Create React App, set the homepage field in package.json and use %PUBLIC_URL% in the template. Then check the built index.html to confirm the prefix came through.

### Does manifest.json do anything in a plain React app?

It supplies the name, theme colour, and icon list used when someone installs the site to a home screen, and Android reads its icons instead of the apple-touch-icon. It does not make the app work offline. That needs a service worker, which neither Vite nor current CRA adds by default.
