---
title: SvelteKit Favicon Generator
description: SvelteKit copies static/ to the build root and app.html is the document shell. Where icon files go, and why %sveltekit.assets% matters for the hrefs.
canonical: https://favicontools.com/platforms/svelte-favicon
---

# SvelteKit Favicon Generator

SvelteKit copies everything in static/ to the root of the build, and the document shell is src/app.html rather than a component. Icon tags belong there so they are in the served HTML before any JavaScript runs.

## static/ and app.html

SvelteKit has two places a file can live and only one of them keeps its name. Anything under static/ is copied to the root of the build untouched, so static/favicon.ico is served at /favicon.ico. Anything imported from src/ goes through Vite and comes out fingerprinted, which is fine for images in a component and useless for an icon requested by a fixed path.

The head itself comes from src/app.html. That file is not a Svelte component — it is the HTML template SvelteKit renders every route into, including error pages, which is why global tags such as icons belong there rather than in a layout.

## Where the files go

```
my-sveltekit-app/
  static/  # copied to the build root
    favicon.png  <- add  # replaces the default
    favicon.ico  <- add
    apple-touch-icon.png  <- add
    icon-192.png  <- add
    icon-512.png  <- add
    manifest.webmanifest  <- add
  src/
    app.html  # the document shell
    routes/
      +layout.svelte
      +page.svelte
  svelte.config.js
```

## src/app.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%sveltekit.assets%/favicon.png" />
    <link rel="icon" href="%sveltekit.assets%/favicon.ico" sizes="any" />
    <link rel="apple-touch-icon" href="%sveltekit.assets%/apple-touch-icon.png" />
    <link rel="manifest" href="%sveltekit.assets%/manifest.webmanifest" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    %sveltekit.head%
  </head>
  <body data-sveltekit-preload-data="hover">
    <div>%sveltekit.body%</div>
  </body>
</html>
```

The skeleton project already ships one of these with a single favicon line. You are extending it, not replacing it.

> **Keep the %sveltekit.assets% placeholder:** It is replaced with the correct prefix for however the app is being served, including a configured base path and the relative paths a fully static build can use. Hardcoding a leading slash works until the site moves off the domain root, then every icon 404s at once.

## Check the small end first

- 16x16
- 32x32
- 48x48
- 96x96
- 180x180

Rendered at true pixel dimensions. The 16px swatch is the one that decides whether a mark works as a favicon.

## SvelteKit favicon FAQ

### Should I use svelte:head for the favicon instead?

No. svelte:head is per-component, so the tag only exists on routes that render that component and arrives with the page rather than with the document. app.html covers every route, including the error page, and puts the tag in the initial HTML.

### The skeleton ships static/favicon.png — do I delete it?

Replace the file and keep the name, or rename it and update the one reference in app.html. Nothing else in the project points at it, so there is no hidden second reference to chase.

### Are files in static/ fingerprinted for cache busting?

No, they are copied byte for byte with their original names. That is what makes a fixed icon path possible, and it also means a long cache header on those files can only be busted by changing the filename.
