Skip to content

Manifest and Icons

Instead of a separate manifest.json file, vite-plugin-pwa lets you define the manifest directly in vite.config.ts. The plugin injects it into every HTML page and adds the necessary <link rel="manifest"> tag automatically. This keeps your PWA configuration in one place alongside the rest of your Vite setup.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig({
plugins: [
react(),
VitePWA({
registerType: 'prompt',
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'robots.txt'],
manifest: {
name: 'My PWA App',
short_name: 'MyApp',
description: 'A Progressive Web App built with Vite and React',
theme_color: '#ffffff',
background_color: '#ffffff',
display: 'standalone',
start_url: '/',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
},
],
},
}),
],
});

The includeAssets option tells Workbox to precache static files that are NOT automatically part of the build output. Without it, files like favicon.ico and apple-touch-icon.png — which you place manually in public/ — would not be included in the service worker’s precache manifest.

includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'robots.txt'],

Adding these here ensures they are cached on the first service worker install, so the browser and iOS home screen always serve them from cache even when the user is offline.

Icon generation with @vite-pwa/assets-generator

Section titled “Icon generation with @vite-pwa/assets-generator”

Instead of manually exporting every icon size from a design tool, you can generate all required sizes from a single SVG source using the @vite-pwa/assets-generator package.

Terminal window
npx @vite-pwa/assets-generator --preset minimal logo.svg

This command reads logo.svg from the current directory and writes all the generated PNG icons into public/. The minimal preset produces the sizes that cover the icons array shown above.

The 180x180 apple-touch-icon.png file must be placed in public/ so Vite copies it into dist/ during the build. iOS uses this image when a user adds your app to their home screen. Reference it in includeAssets so Workbox precaches it.

The favicon.ico file follows the same rule — it lives in public/ and should be listed in includeAssets.

Icon sizePurpose
192x192Standard Android home screen
512x512Splash screen / install prompt
512x512 maskableAdaptive icon on Android
180x180Apple Touch Icon (iOS home screen)
OptionBenefitCost
Define the manifest through vite-plugin-pwa’s configGenerates multiple icon sizes automatically, no manifest.json file to maintain by handTied to the plugin’s specific config syntax, one more option surface to learn
Write a static manifest.json yourselfDirect control, no plugin abstraction in the wayYou maintain every icon size and keep it in sync with the build entirely by hand
  • Providing only a single icon size in the config, so the plugin cannot generate the full set Android/iOS expect.
  • Forgetting to set the base path to match the real deployment target, breaking icon paths in the manifest at production build time.
  • Not generating a separate maskable icon, so the icon gets clipped oddly on Android as if nothing had been configured at all.

The Vite PWA ecosystem is used by real projects like Elk, the open-source Mastodon client, which generates its manifest and full icon set from a single vite-plugin-pwa config (Elk’s package.json lists vite-plugin-pwa), and many VitePress sites use the same plugin to make their documentation installable with barely any manifest code of their own.

Where do you define the manifest when using vite-plugin-pwa?
What does includeAssets do?
Which tool generates all PWA icon sizes from a single SVG?
What icon purpose value allows Android to apply an adaptive mask to your icon?