Nico Deblauwe

The Day that Bunny Fonts Went Silent

Created May 22, 2026

On an otherwise perfectly ordinary morning, one of my sites loaded a bit slower than usual, and everything looked just wrong. Headers were suddenly chunky, buttons felt like they’d borrowed a typewriter, and the whole interface had the subtle charm of a 2004 school project.

The culprit? fonts.bunny.net had decided to take the day off.

It’s the kind of outage that doesn’t crash your app, but does make it look like it forgot to brush its teeth. The takeaway: we needed resilience, not panic.

Instead of sprinkling font <link> tags across 50+ templates (multi-tenant platform context), we pulled all font delivery into one place: a Blade component. One knob. One switch. One predictable output.

The new interface

Templates now use:

<x-font-provider families="nunito:400,600,700" />

instead of:

<link rel="preconnect" href="https://fonts.bunny.net" crossorigin>
<link href="https://fonts.bunny.net/css?family=nunito:400,600,700" rel="stylesheet" />

The font provider is set through a .env variable, but because it’s a flexible component, we can override the provider and preconnect behavior when needed:

<x-font-provider families="dm-sans:400,600,700" provider="google" :preconnect="true" />

High-level implementation outline

At a high level, the component class normalizes inputs, selects the provider from config, builds the final URL, and optionally renders preconnect tags:

final class FontProvider extends Component
{
    public function __construct(
        ?string $provider = null,
        string $families = '',
        bool $preconnect = true,
    ) {
        // normalize inputs, select provider from config
    }

    public function render(): View|Closure|string
    {
        // build URL + optional preconnect tags
        return view('components.font-provider');
    }
}

Configuration

Configuration lives in config/app.php so we can switch providers via environment variables:

'fonts' => [
    'provider' => env('FONT_PROVIDER', 'bunny'),
    'providers' => [
        'bunny' => [
            'base_url' => 'https://fonts.bunny.net/css',
            'preconnects' => [
                ['url' => 'https://fonts.bunny.net'],
            ],
            'css2' => false,
        ],
        'google' => [
            'base_url' => 'https://fonts.googleapis.com/css2',
            'preconnects' => [
                ['url' => 'https://fonts.googleapis.com'],
                ['url' => 'https://fonts.gstatic.com', 'crossorigin' => true],
            ],
            'css2' => true,
        ],
    ],
],

This gives you:

What to watch out for (Bunny vs Google)

I switched many years back to the Bunny side. Laravel starter kits moved over, I followed, and I never regretted it. Until Bunny briefly reminded me that every external dependency is, at heart, a tiny leap of faith.

Bunny Fonts is a drop-in replacement for Google Fonts, but “drop-in” isn’t quite “identical anymore”:

In other words: same outcome, slightly different dialect. So not the most beautiful code in the blade component, but hey, that is not a big worry.

The happy ending

When fonts.bunny.net takes a coffee break, we don’t scramble. We flip an env value, the component swaps providers, and pages keep their polished look.

No customer reports. No frantic “did we deploy something?” messages. Just one developer quietly muttering, “Please come back, I liked you,” at a CDN.

And when Bunny returns: switch back, move on, and keep the fonts where they belong—quietly doing their job.

(Still crossing my fingers that Bunny stays up. But now, at least, we have a parachute.)