Web Assets
Favicon and PWA assets for a modern website, with optional Legacy Browser Support.
Modern-first export: covers current browsers, PWAs, and the iOS Add-to-Home-Screen surface out of the box. Legacy Browser Support is opt-in.
Default set
your-app/public/
├── favicon.ico # 16, 32, 48 — legacy + implicit /favicon.ico probe
├── icon.svg # vector — modern tabs, hi-DPI
├── icon-192.png # PWA install icon
├── icon-512.png # large PWA icon / splash
├── icon-512-maskable.png # Android adaptive (full-bleed, safe-zone padded)
├── apple-touch-icon.png # 180 — iOS Add to Home Screen
├── manifest.webmanifest
└── SETUP.mdIf your design uses a built-in icon from Lucide, the ZIP may also include ATTRIBUTION.txt.
Paste this into <head>
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" type="image/svg+xml" href="/icon.svg">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#ffffff">Order matters: browsers pick the last matching rel="icon" they support, so SVG comes after ICO.
For per-scheme browser chrome colors, split theme-color:
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#ffffff">
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#000000">Next.js (App Router)
// app/layout.tsx
export const metadata = {
icons: {
icon: [
{ url: '/favicon.ico', sizes: 'any' },
{ url: '/icon.svg', type: 'image/svg+xml' },
],
apple: '/apple-touch-icon.png',
},
manifest: '/manifest.webmanifest',
};manifest.webmanifest
The shipped manifest is a stub — edit name, short_name, and theme_color to match the app:
{
"name": "Your App Name",
"short_name": "App",
"icons": [
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" },
{
"src": "/icon-512-maskable.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}Maskable icon
icon-512-maskable.png is generated from your design with three forced adjustments so it survives Android's adaptive-icon mask:
- Padding is zeroed (background fills edge to edge).
- Artwork is scaled to fit the inner 80% safe zone (W3C requirement).
- Border radius is removed (the OS supplies the clip shape).
The source design is untouched; these only apply at export time.
Legacy Browser Support (opt-in)
Toggle this on if the project still needs IE / old Edge pinned-tile support or explicit small PNG fallback files. Adds:
| File | When |
|---|---|
icon-16.png, icon-32.png | Browsers that ignore ICO |
mstile-150x150.png + browserconfig.xml | Legacy Windows pinned tiles |
For most new projects, skip this — favicon.ico already handles legacy browsers that probe for it.
Compatibility map
| Surface | Asset |
|---|---|
| Modern browser tab | icon.svg |
| Legacy browser tab | favicon.ico |
| iOS Add to Home Screen | apple-touch-icon.png |
| PWA install prompt | manifest.webmanifest + icon-192.png, icon-512.png |
| Android adaptive icon | icon-512-maskable.png |
| Legacy Windows pinned sites | browserconfig.xml, mstile-150x150.png (opt-in) |
Validate after install
Run these checks on the deployed site, not only in the editor.
1. Files are reachable
Open each URL directly in the browser (replace host with yours):
https://your-site.com/favicon.ico
https://your-site.com/icon.svg
https://your-site.com/apple-touch-icon.png
https://your-site.com/manifest.webmanifest
https://your-site.com/icon-192.png
https://your-site.com/icon-512.pngEach should return 200 with the expected content type.
2. <head> links are present
DevTools → Elements → inspect <head>:
- Two
rel="icon"entries (ICO + SVG) in that order rel="apple-touch-icon"pointing at/apple-touch-icon.pngrel="manifest"pointing at/manifest.webmanifestmeta name="theme-color"matching your manifest stub (edit both to your brand color)
3. Manifest parses
DevTools → Application → Manifest:
- No parse errors
- Icons lists 192, 512, and maskable 512 with correct paths
- Edit
name,short_name, andtheme_colorin the shipped stub before shipping
4. Favicon in the tab
Hard refresh (⌘+Shift+R / Ctrl+Shift+R) or use a private window. Browsers cache favicons independently of HTML cache — seeing the old icon after a successful deploy is common.
5. Cache while iterating
During local development, append a query string to the SVG link:
<link rel="icon" type="image/svg+xml" href="/icon.svg?v=2">Bump the version when you replace the file. Remove or stabilize the query param for production once assets are final.
Manifest serving
manifest.webmanifest must be served as application/manifest+json or application/json. Next.js and Vercel do this by default. Static hosts sometimes serve .webmanifest as application/octet-stream — override the MIME type if the Application panel reports a parse failure.
Icon not updating, PWA icon missing, manifest errors — see Troubleshooting.