Get "PHP 8 in a Nuthshell" (Now comes with PHP 8.3)
Amit Merchant

Amit Merchant

A blog on PHP, JavaScript, and more

Environment-aware Favicons

When working on a website, sometimes you can’t distinguish between the environments just by looking at the tabs if you have both the production and local environments opened side by side. And this can lead to confusion.

This is where environment-aware favicons come into play. They help you distinguish between the environments by changing the favicon of the website based on the environment.

Josh Comeau recently tweeted about this idea and I found it quite interesting. He shared how he implemented this feature in his Next-powered blog with App Router. This is what it looks like.

Josh's Blog

He kept the light favicon for the local environment and the dark favicon for the production environment.

Here’s what the app/icon.tsx file looks like in his blog.

import { readFile } from 'fs/promises';
import { NextResponse } from 'next/server';

export default async function Icon() {
  try {
    const image = await readFile(
      process.env.NODE_ENV === 'production'
        ? './public/favicon.png'
        : './public/favicon-dev.png'

    return new NextResponse(image, {
      headers: {
        'Content-Type': 'image/png',
  } catch (error) {
    return new NextResponse('Internal Server Error', { status: 500 });

As you can tell, the code is pretty straightforward. It reads the favicon.png file in the production environment and favicon-dev.png in the development environment using the process.env.NODE_ENV variable. And then, it returns the image as a response.

It’s pretty simple to implement in other frameworks as well. For instance, in Laravel, you can use the following code to achieve the same.

Route::get('/favicon.ico', function () {
    $favicon = file_get_contents(
            ? public_path('favicon.ico')
            : public_path('favicon-dev.ico')

    return response($favicon)
        ->header('Content-Type', 'image/x-icon');

I think this is a really cool feature to have configured on your website. It’s a small detail but it can make a big difference in making the development workflow less confusing.

Like this article? Consider leaving a


👋 Hi there! I'm Amit. I write articles about all things web development. You can become a sponsor on my blog to help me continue my writing journey and get your brand in front of thousands of eyes.