How to Add a Favicon with html-webpack-plugin
Add a favicon with html-webpack-plugin's favicon option, prepare SVG logo artwork for small sizes, add a fallback icon, and confirm the tag and file in your build.
Contents
The short answer
Pass the path of your icon file to the favicon option when you create the plugin. When webpack builds, html-webpack-plugin copies that file into the output folder and adds a link tag pointing to it in the generated HTML. You do not need to write the link tag yourself. This works for a single icon file, such as an ICO, PNG or SVG.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...entry, output, loaders
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
favicon: path.resolve(__dirname, 'src/assets/favicon.ico'),
}),
],
};
Building the path with path.resolve and __dirname gives an absolute path. This avoids depending on the folder webpack treats as its working context, which differs between projects. If your output configuration sets a publicPath, the plugin uses it as the start of the icon's address in the generated tag.
Terms used in this guide
- Favicon: the small icon a browser shows in tabs, bookmarks and history for a site.
- Vector artwork: an image defined by mathematical paths, not pixels, so it can be scaled without losing sharpness. SVG is the vector format browsers read directly.
- viewBox: the attribute on an SVG's root element that sets its internal coordinate area. A square viewBox helps the icon fill a square favicon slot without distortion.
- Outlined text: lettering converted from live font characters into plain paths, so it displays correctly without the font being installed.
- Raster fallback: a pixel-based icon (ICO or PNG) for browsers or contexts that do not use an SVG favicon.
Step 1: Prepare the logo artwork for favicon size
A favicon is shown very small, so a full logo with a wordmark and fine detail usually becomes unreadable. These are design recommendations, not technical requirements. Use a simplified mark or monogram, place it on a square artboard with a square viewBox, and remove thin strokes and small details that blur together at small sizes.
- Convert any text to outlines so the icon does not depend on a font.
- Open the SVG in a text editor and confirm it contains paths and shapes, not an embedded bitmap image. A .svg extension does not prove the file is vector-only.
- Remove editor metadata, hidden layers and unused definitions to keep the file small.
- If you plan an ICO or PNG fallback, export it from the same simplified artwork so both versions match.
- Confirm you have permission to use the logo. Having the file does not grant reuse rights.
Step 2: Choose single-icon or multi-icon setup
The favicon option takes one file and creates one link tag. If one ICO or PNG is enough, use the configuration above and continue to Step 4.
You can also point the option at an SVG. Support for SVG favicons varies by browser, so a common pattern is to provide an SVG together with a raster fallback. The favicon option cannot output two icons. For that setup, declare the link tags in your HTML template instead.
Step 3 (multi-icon only): Declare icons in the template
Add the link tags to the template you give html-webpack-plugin. The plugin keeps the template's existing markup when it builds the final HTML.
<head>
<meta charset="utf-8">
<title>My site</title>
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
</head>
The plugin will not copy files referenced only in template markup, so copy them to the output folder yourself. One way is the separate copy-webpack-plugin package.
const CopyWebpackPlugin = require('copy-webpack-plugin');
// inside plugins: [...]
new CopyWebpackPlugin({
patterns: [
{ from: 'src/assets/favicon.ico', to: 'favicon.ico' },
{ from: 'src/assets/favicon.svg', to: 'favicon.svg' },
],
}),
If you use this approach, remove the favicon option from html-webpack-plugin to avoid a duplicate link tag. The addresses in the template assume the site is served from the domain root. Change them if your app is deployed under a subpath.
Step 4: Verify the result
- Run a production build and check that the icon file or files are in the output folder.
- Open the generated index.html and confirm there is exactly one link tag for each intended icon, with the expected address.
- Load the page, open the browser's developer tools, and check in the Network panel that each icon request succeeds instead of returning a not-found error.
- Browsers cache favicons heavily. If an old icon still appears, use a private window or clear the site's cached data before deciding the setup has failed.
- With webpack-dev-server, files are served from memory and may not appear on disk. Check the served page and the network request instead.
Gaps to check against your own project
No project-specific details were provided, so this guide does not cover your versions of webpack and html-webpack-plugin, your output and publicPath settings, or which browsers you must support. Option behavior and the exact tag markup can change between plugin versions. Check the documentation for the version in your package manifest, and test icon display in the browsers your audience uses.