Remix Favicon Guide
Master favicon setup in Remix: public folder, links function, meta exports, and React-based full-stack framework implementation.
Remix Favicon Setup
1. Public Folder
Place in public/
2. Links Function
Export from root
3. Done!
Auto-included
Step 1: File Structure
Remix Directory Layout
my-remix-app/
public/ ? Place all favicons here
favicon.ico
favicon-16x16.png
favicon-32x32.png
apple-touch-icon.png
android-chrome-192x192.png
android-chrome-512x512.png
site.webmanifest
app/
root.tsx ? Configure links here
routes/
entry.client.tsx
entry.server.tsx
remix.config.jsNote: Files in
public/ are served at root URL. Accessible at /favicon.icoStep 2: Configure root.tsx
app/root.tsx
Complete root.tsx Example
import type { LinksFunction, MetaFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
export const links: LinksFunction = () => [
// Standard favicons
{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" },
{ rel: "icon", type: "image/png", sizes: "32x32", href: "/favicon-32x32.png" },
{ rel: "icon", type: "image/png", sizes: "16x16", href: "/favicon-16x16.png" },
// Apple Touch Icon
{ rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.png" },
// Android/Chrome
{ rel: "icon", type: "image/png", sizes: "192x192", href: "/android-chrome-192x192.png" },
{ rel: "icon", type: "image/png", sizes: "512x512", href: "/android-chrome-512x512.png" },
// Web App Manifest
{ rel: "manifest", href: "/site.webmanifest" },
];
export const meta: MetaFunction = () => [
{ name: "theme-color", content: "#3992ff" },
];
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 />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}Per-Route Favicon Override
Route-Specific Favicons
app/routes/blog.tsx Example
import type { LinksFunction } from "@remix-run/node";
export const links: LinksFunction = () => [
{ rel: "icon", type: "image/x-icon", href: "/favicon-blog.ico" },
];
export default function Blog() {
return (
<div>
<h1>Blog (Custom Favicon)</h1>
</div>
);
}Note: Route-specific links are merged with root links. Later declarations override earlier ones.
PWA Manifest Configuration
public/site.webmanifest
{
"name": "My Remix App",
"short_name": "Remix App",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#3992ff",
"background_color": "#ffffff",
"display": "standalone",
"start_url": "/"
}Build & Deploy
Production Build
Build Commands
# Development
npm run dev
# Production build
npm run build
# Start production server
npm startDeployment Platforms
- Vercel: Auto-detects Remix
- Netlify: Use Remix adapter
- Fly.io: Official Remix deployment
- Cloudflare Pages: Use Cloudflare adapter
Remix Favicon Best Practices
? Best Practices
- Place all favicons in
public/folder - Export links from
root.tsx - Use TypeScript LinksFunction type
- Include manifest for PWA support
- Set theme-color in meta function
- Test both dev and production builds
- Use route-specific favicons when needed
- Verify public folder in build output
? Common Mistakes
- Placing favicons outside
public/ - Forgetting to export links function
- Not including Links component in root
- Missing manifest link
- Wrong paths (e.g.,
./favicon.ico) - Not testing production build
- Missing Meta component
- Not clearing build cache
Generate Remix-Ready Favicons
Create optimized favicon packages for Remix applications
Generate Favicons