Four tags, not twenty
Favicon generators are notorious for handing back thirty files and twenty <link> elements: Windows 8 tiles, a browserconfig.xml, six sizes of apple-touch-icon, icons for devices that stopped shipping a decade ago. Every one of those is bytes in the <head> of every page you serve, forever, for nothing.
What current browsers actually read is four things: the .ico for legacy requests and the Windows taskbar, one 180px apple-touch-icon for iOS home screens, the web manifest for Android and installed web apps, and optionally an SVG icon where it is supported. That is the set this page emits, and the rest is deliberately absent.
The .ico container, and why it is written here by hand
An .ico is a six-byte header, a sixteen-byte directory entry per image, and the image payloads laid end to end. Since Windows Vista those payloads may be complete PNG files stored verbatim, which removes the one awkward part of the format: the old BMP variant with its upside-down rows and its separate transparency mask. The whole writer is about sixty lines, which is smaller than any library that does it.
One detail catches everyone: a dimension of 256 is stored as 0, because the field is a single byte and 256 does not fit in one. This tool tops out at 64px inside the .ico anyway. The container has no compression of its own, so a 256px entry adds its full PNG weight to a file that gets requested on every page load, and the large sizes belong in separate PNGs where the manifest can point at them.
16 pixels is where icons die
The preview above shows each size at its true pixel dimensions rather than blown up, because the blown-up version is a lie. A logo with a tagline, a thin outline, or three colours of similar lightness turns into a grey smudge at 16px, and you cannot see that in a 64px preview. The fix is never a better export; it is a simplified mark. One shape, one strong colour, no text.
Common problems
- The Apple icon has a black background. iOS composites the touch icon onto black rather than honouring transparency, so a transparent logo vanishes. That one size is generated on white here for exactly this reason; everything else keeps its alpha.
- Android cropped the corners off. Adaptive icons are masked to a circle or a squircle. The manifest here marks the 512px icon
maskable, but you still need roughly 20% padding inside the artwork, or the mask eats it. - The browser still shows the old icon. Favicons are cached aggressively and often ignore a normal reload. Try a private window, or add a query string to the link while developing.
- Nothing shows at all. The files have to be at the paths the tags name, which for a favicon means the site root. A framework that hashes asset filenames will break
/favicon.icounless it is placed in the static public directory.
Frequently asked questions
Do I still need favicon.ico in 2026?
Yes, and mostly for a boring reason: browsers request /favicon.ico from the site root whether or not you asked them to, so not having one is a 404 on every visit. It is also what the Windows taskbar and desktop shortcuts read.
Should I use an SVG favicon?
As an addition, not a replacement. It is sharp at every size and can respond to dark mode with a media query inside the SVG itself, which is genuinely nice. It is also not read by Safari or by the Windows taskbar, so the .ico stays.
Is my logo uploaded?
No. Every size is rendered in a Web Worker on your device, the .ico is assembled from those bytes in JavaScript, and the ZIP is built in memory. Watch the network tab while you generate a set: nothing leaves.
Why is the ZIP not compressed?
Everything in it is already a PNG, and deflating a PNG saves a fraction of a percent. The archive uses store mode, which every operating system opens natively.