---
title: Laravel Favicon Generator
description: Laravel serves icons from public/ and links them in the Blade layout. Where files go with Vite, and why the document root must be public/.
canonical: https://favicontools.com/platforms/laravel-favicon
---

# Laravel Favicon Generator

Laravel has no icon convention of its own. Files in public/ are served at the site root, and the link tags belong in your Blade layout's head. Getting the web server's document root wrong is the most common reason a perfectly placed favicon.ico still 404s.

## public/ is the web root

In a correctly configured Laravel app the web server's document root is the public/ directory, not the project root. That means public/favicon.ico is requested as /favicon.ico, and anything you put next to artisan is not URL-addressable at all.

The tags themselves live in the Blade layout most pages extend, typically resources/views/layouts/app.blade.php or the welcome view if you have not built a layout yet. Vite bundles CSS and JS; it does not invent favicon tags for you.

## Where the files go

```
my-laravel-app/
  public/  # document root
    favicon.ico  <- add
    favicon-32x32.png  <- add
    apple-touch-icon.png  <- add  # 180x180
    icon-192.png  <- add
    icon-512.png  <- add
    site.webmanifest  <- add
    index.php
  resources/
    views/
      layouts/
        app.blade.php  # link tags go here
  vite.config.js
```

Keep icons in public/ with stable names. Putting them under resources/ and hashing them with Vite is optional cache-busting, not the default path.

## Blade layout head

```html
{{-- resources/views/layouts/app.blade.php --}}
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>{{ config('app.name') }}</title>

  <link rel="icon" href="{{ asset('favicon.ico') }}" sizes="any">
  <link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicon-32x32.png') }}">
  <link rel="apple-touch-icon" href="{{ asset('apple-touch-icon.png') }}">
  <link rel="manifest" href="{{ asset('site.webmanifest') }}">

  @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
```

asset() prefixes the configured asset URL, which matters when the app is not served from the domain root. Hardcoding /favicon.ico skips that.

## public/ vs Vite-processed icons

| Approach | Use when | Trade-off |
| --- | --- | --- |
| Files in public/ | Almost every app | Stable URLs; bust cache by renaming |
| Vite::asset(...) from resources/ | You already version images through Vite | Hashed filenames; more moving parts |
| No link tags, only public/favicon.ico | Quick local check | Misses PNG, apple-touch-icon, manifest |

> **Document root must be public/:** If the URL bar shows /public/favicon.ico, or requests for /favicon.ico 404 while the file exists on disk, the vhost or Heroku/Forge/Valet docroot is pointed at the project root. Fix that before changing Blade tags. asset() and the browser both assume public/ is /.

## Laravel favicon FAQ

### Do I need to rebuild Vite after changing the favicon?

Not if the files live in public/ and you referenced them with asset(). Vite only needs a rebuild when the icons are part of its input graph via Vite::asset or an imported URL in CSS/JS.

### The tab still shows the old Laravel icon.

Browsers cache favicons aggressively. Confirm the published HTML points at your file, then load the site in a private window. If you replaced public/favicon.ico in place, rename it (favicon-v2.ico) or hard-refresh once so the URL itself changes.

### Where does the default favicon come from?

Laravel's skeleton ships a favicon.ico in public/. Replace that file and add the rest of the set beside it. Nothing in the framework regenerates it on deploy.
