SvelteKit app.html Favicon: The HTML Template Setup Guide
You've wired up your SvelteKit routes, polished the layouts, and deployed the build. But when you open your live tab, you see the default Svelte logo — or worse, a blank white square. The fix usually lives in one specific file: app.html.
app.html is the HTML shell that SvelteKit uses to render every page on both the server and client. According to the SvelteKit project structure docs, this template sits at the root of src/ and is the only place where you can inject markup that survives hydration on every route. That makes it the perfect home for your favicon <link> tags.
Why app.html and not the layout?
You can add favicon tags inside a +layout.svelte file's <svelte:head> block, and it will work for most routes. But app.html is rendered first, before any layout or component code runs. That gives it two real advantages:
Favicon requests fire on the very first byte the browser receives, which speeds up tab rendering.
Tags injected from +layout.svelte can be missed by crawlers and bots that don't execute JavaScript. app.html always ships static HTML.
Prerequisites
You'll need:
A working SvelteKit project (2.x or later).
Your favicon files ready inside static/. For a complete stack, prepare a 32×32 favicon.ico, a 180×180 apple-touch-icon.png, an SVG, and optionally a site.webmanifest.
If you don't have those files yet, generate them with Mzu favicondl from any source image — it outputs the full size package in one click.
Step-by-step: Add favicon link tags to app.html
1. Locate your app.html file
Open src/app.html. By default, it looks roughly like this:
Notice the %sveltekit.assets% and %sveltekit.head% placeholders — those get replaced at build time. You can keep them and add more tags right above or below.
2. Replace the default favicon line
The starter template ships with a single favicon.png line. Delete it and replace it with a complete set of tags. The HTML spec defines rel='icon' as the standard way to declare icons, so stick to that attribute.
The SVG goes first so modern browsers prefer it. The ICO acts as a fallback for older browsers. Apple Touch and manifest come last because they target specific platforms.
3. Add dark mode support
If your SVG icon needs a different look in dark tabs (and these days, who isn't running a dark theme?), declare two media-specific sources. This is the same technique we cover in our favicon dark mode guide:
The browser evaluates the media attribute and picks the matching icon.
4. Drop your files into static/
SvelteKit serves everything inside static/ from the site root. Place each favicon file there with the exact filename referenced in your tags. A clean structure looks like:
Vite caches the HTML shell aggressively. After editing app.html, stop your dev server with Ctrl+C and run npm run dev again. Otherwise you may keep seeing stale markup.
Common pitfalls
Putting favicon tags in the body. Browsers only look at <head> for icon declarations. Anything inside <body> is ignored, even when the file is named app.html. If yours aren't appearing, this is the first thing to check.
Mismatched filenames between tags and static/. Case sensitivity matters on Linux deploys. favicon.ICO and favicon.ico are different files. Match the names exactly.
Stale icons after deployment. Browsers cache favicons aggressively — sometimes for weeks. If you swap files and don't see updates, append a query string or content hash, then redeploy. The same pattern works for any static asset in static/.
Double-encoding SVG attributes. If you copy a snippet that uses type="image/svg+xml" with double quotes into the app.html shell, Vite can mangle it. Stick with single quotes inside HTML attributes to keep the build happy.
Wrapping up
The app.html template is the cleanest place to declare favicons in SvelteKit because it runs before any JavaScript and ships with every page response. Drop a complete SVG + ICO + Apple Touch stack into static/, wire the corresponding <link> tags into <head>, and you'll have a crisp icon on every browser tab from the very first paint.
For a broader look at SvelteKit favicon options — including the +layout.svelte approach and dynamic icons — see our main SvelteKit favicon guide. And if you need the actual icon files, Mzu favicondl generates the full size stack from any source image in seconds.
SvelteKit 라우트를 연결하고, 레이아웃을 다듬고, 빌드를 배포하셨나요? 그런데 라이브 탭을 열면 기본 Svelte 로고가 보이거나, 더 나쁘게는 하얀 빈 사각형만 보일 수 있습니다. 이 문제는 대개 한 특정 파일, 즉 app.html에서 해결됩니다.
app.html은 SvelteKit이 서버와 클라이언트 양쪽에서 모든 페이지를 렌더링할 때 사용하는 HTML 셸입니다. SvelteKit 프로젝트 구조 문서에 따르면, 이 템플릿은 src/의 루트에 있으며, 모든 라우트에서 하이드레이션 후에도 유지되는 마크업을 주입할 수 있는 유일한 곳입니다. 따라서 파비콘 <link> 태그를 넣기에 가장 적합한 위치입니다.
왜 레이아웃이 아니라 app.html인가?
+layout.svelte 파일의 <svelte:head> 블록 안에 파비콘 태그를 추가할 수도 있으며, 대부분의 라우트에서 작동합니다. 그러나 app.html은 레이아웃이나 컴포넌트 코드가 실행되기 전에 먼저 렌더링됩니다. 이로 인해 두 가지 실질적인 이점이 있습니다:
파비콘 요청이 브라우저가 받는 첫 바이트에서 발생하므로 탭 렌더링 속도가 빨라집니다.
+layout.svelte에서 주입된 태그는 JavaScript를 실행하지 않는 크롤러와 봇이 놓칠 수 있습니다. app.html은 항상 정적 HTML을 제공합니다.
사전 요구 사항
필요한 것은 다음과 같습니다:
작동하는 SvelteKit 프로젝트(2.x 이상).
static/ 안에 준비된 파비콘 파일. 완전한 스택을 위해 32×32 favicon.ico, 180×180 apple-touch-icon.png, SVG, 그리고 선택적으로 site.webmanifest를 준비하세요.
아직 해당 파일이 없다면, Mzu favicondl을 사용하여 원본 이미지에서 생성하세요. 한 번의 클릭으로 전체 크기 패키지를 출력합니다.
Vite는 HTML 셸을 적극적으로 캐시합니다. app.html을 편집한 후에는 Ctrl+C로 개발 서버를 중지하고 npm run dev를 다시 실행하세요. 그렇지 않으면 이전 마크업이 계속 표시될 수 있습니다.
흔한 함정
파비콘 태그를 body에 넣는 경우. 브라우저는 아이콘 선언을 위해 <head>만 확인합니다. <body> 안의 내용은 파일 이름이 app.html이더라도 무시됩니다. 파비콘이 나타나지 않는다면 가장 먼저 확인할 사항입니다.
태그와 static/의 파일 이름 불일치. Linux 배포에서는 대소문자 구분이 중요합니다. favicon.ICO와 favicon.ico는 다른 파일입니다. 이름을 정확히 일치시키세요.
배포 후 오래된 아이콘. 브라우저는 파비콘을 적극적으로 캐시하며 때로는 몇 주 동안 유지합니다. 파일을 교체했는데 업데이트가 보이지 않으면 쿼리 문자열이나 콘텐츠 해시를 추가한 후 다시 배포하세요. 이 패턴은 static/의 모든 정적 자산에 동일하게 적용됩니다.
SVG 속성의 이중 인코딩.type="image/svg+xml"처럼 큰따옴표를 사용하는 스니펫을 app.html 셸에 복사하면 Vite가 망가뜨릴 수 있습니다. HTML 속성에는 작은따옴표를 사용하여 빌드가 정상 작동하도록 하세요.
마무리
app.html 템플릿은 JavaScript보다 먼저 실행되고 모든 페이지 응답에 포함되므로 SvelteKit에서 파비콘을 선언하는 가장 깔끔한 위치입니다. 완전한 SVG + ICO + Apple Touch 스택을 static/에 넣고 해당 <link> 태그를 <head>에 연결하면 첫 페인트부터 모든 브라우저 탭에 선명한 아이콘이 표시됩니다.
SvelteKit 파비콘 옵션에 대한 더 넓은 시각(+layout.svelte 접근 방식 및 동적 아이콘 포함)은 메인 SvelteKit 파비콘 가이드를 참조하세요. 실제 아이콘 파일이 필요하다면 Mzu favicondl이 원본 이미지에서 전체 크기 스택을 몇 초 만에 생성합니다.
Has configurado tus rutas de SvelteKit, pulido los layouts y desplegado la build. Pero cuando abres tu pestaña en vivo, ves el logo de Svelte por defecto — o peor, un cuadrado blanco vacío. La solución suele estar en un archivo específico: app.html.
app.html es la plantilla HTML que SvelteKit usa para renderizar cada página tanto en el servidor como en el cliente. Según la documentación de estructura de proyecto de SvelteKit, esta plantilla se encuentra en la raíz de src/ y es el único lugar donde puedes inyectar marcado que sobrevive a la hidratación en cada ruta. Eso lo convierte en el hogar perfecto para tus etiquetas <link> de favicon.
¿Por qué app.html y no el layout?
Puedes añadir etiquetas de favicon dentro del bloque <svelte:head> de un archivo +layout.svelte, y funcionará para la mayoría de rutas. Pero app.html se renderiza primero, antes de que se ejecute cualquier layout o código de componente. Eso le da dos ventajas reales:
Las solicitudes de favicon se disparan con el primer byte que recibe el navegador, lo que acelera el renderizado de la pestaña.
Las etiquetas inyectadas desde +layout.svelte pueden ser ignoradas por rastreadores y bots que no ejecutan JavaScript. app.html siempre envía HTML estático.
Requisitos previos
Necesitarás:
Un proyecto SvelteKit funcional (2.x o posterior).
Tus archivos de favicon listos dentro de static/. Para una pila completa, prepara un favicon.ico de 32×32, un apple-touch-icon.png de 180×180, un SVG y, opcionalmente, un site.webmanifest.
Si aún no tienes esos archivos, genéralos con Mzu favicondl desde cualquier imagen de origen; genera el paquete completo de tamaños en un clic.
Paso a paso: Añadir etiquetas de favicon a app.html
1. Localiza tu archivo app.html
Abre src/app.html. Por defecto, se ve más o menos así:
Observa los placeholders %sveltekit.assets% y %sveltekit.head%; se reemplazan en tiempo de build. Puedes mantenerlos y añadir más etiquetas justo encima o debajo.
2. Reemplaza la línea de favicon por defecto
La plantilla inicial incluye una única línea con favicon.png. Bórrala y reemplázala con un conjunto completo de etiquetas. La especificación HTML define rel='icon' como la forma estándar de declarar iconos, así que usa ese atributo.
El SVG va primero para que los navegadores modernos lo prefieran. El ICO actúa como respaldo para navegadores antiguos. Apple Touch y manifest van al final porque se dirigen a plataformas específicas.
3. Añade soporte para modo oscuro
Si tu icono SVG necesita un aspecto diferente en pestañas oscuras (y hoy en día, ¿quién no usa un tema oscuro?), declara dos fuentes con media queries. Esta es la misma técnica que cubrimos en nuestra guía de favicon en modo oscuro:
El navegador evalúa el atributo media y selecciona el icono correspondiente.
4. Coloca tus archivos en static/
SvelteKit sirve todo lo que está dentro de static/ desde la raíz del sitio. Coloca cada archivo de favicon allí con el nombre exacto que referencias en tus etiquetas. Una estructura limpia se ve así:
Vite cachea agresivamente la plantilla HTML. Después de editar app.html, detén tu servidor de desarrollo con Ctrl+C y ejecuta npm run dev de nuevo. De lo contrario, podrías seguir viendo marcado obsoleto.
Errores comunes
Poner etiquetas de favicon en el body. Los navegadores solo buscan declaraciones de iconos en <head>. Cualquier cosa dentro de <body> se ignora, incluso si el archivo se llama app.html. Si los tuyos no aparecen, esto es lo primero que debes revisar.
Nombres de archivo que no coinciden entre las etiquetas y static/. La sensibilidad a mayúsculas importa en despliegues Linux. favicon.ICO y favicon.ico son archivos diferentes. Haz coincidir los nombres exactamente.
Iconos obsoletos después del despliegue. Los navegadores cachean los favicons agresivamente — a veces durante semanas. Si cambias archivos y no ves actualizaciones, añade una cadena de consulta o un hash de contenido, y vuelve a desplegar. El mismo patrón funciona para cualquier activo estático en static/.
Atributos SVG con doble codificación. Si copias un fragmento que usa type="image/svg+xml" con comillas dobles dentro de la plantilla app.html, Vite puede dañarlo. Usa comillas simples dentro de los atributos HTML para mantener la build feliz.
Conclusión
La plantilla app.html es el lugar más limpio para declarar favicons en SvelteKit porque se ejecuta antes de cualquier JavaScript y se envía con cada respuesta de página. Coloca una pila completa de SVG + ICO + Apple Touch en static/, conecta las etiquetas <link> correspondientes en <head>, y tendrás un icono nítido en cada pestaña del navegador desde el primer pintado.
Para una visión más amplia de las opciones de favicon en SvelteKit — incluyendo el enfoque con +layout.svelte e iconos dinámicos — consulta nuestra guía principal de favicon en SvelteKit. Y si necesitas los archivos de icono reales, Mzu favicondl genera la pila completa de tamaños desde cualquier imagen de origen en segundos.
Generate Your SvelteKit Favicon Stack
Upload any image and get a complete favicon package — SVG, ICO, Apple Touch, and manifest — ready to drop into static/.