Blaze
Pre-compile Blade components for blazing fast rendering performance
Install / Use
/learn @livewire/BlazeREADME
🔥 Blaze
Speed up your Laravel app with optimized Blade component rendering.
Rendering 25,000 anonymous components:
Without Blaze ████████████████████████████████████████ 500ms
With Blaze █ 13ms
Introduction
Out of the box, Blaze is a drop-in replacement for anonymous Blade components that requires no changes to your existing code.
It works by compiling your templates into optimized PHP functions instead of using the standard rendering pipeline — eliminating 91-97% of the overhead while maintaining near full feature parity with Blade.
For even greater performance, Blaze offers two additional strategies. These require extra configuration and careful consideration:
- Memoization: caching for repeated renders
- Folding: pre-rendering into static HTML
Installation
You may install Blaze via Composer:
composer require livewire/blaze:^1.0
[!TIP] If you're using Flux UI, simply install Blaze and you're ready to go — no configuration needed!
Getting started
There are two ways to enable Blaze:
A) Add the @blaze directive to individual components — great for trying it out or enabling Blaze on specific templates.
B) Optimize entire directories from your service provider — ideal for optimizing many components at once.
After enabling Blaze with either approach, clear your compiled views:
php artisan view:clear
Option A: The @blaze directive
Add @blaze to the top of any anonymous component to enable Blaze for that template:
@blaze
<button {{ $attributes }}>
{{ $slot }}
</button>
Strategies may be specified as arguments:
@blaze(memo: true)
@blaze(fold: true)
Option B: Optimize directories
Call Blaze::optimize() in your AppServiceProvider to enable Blaze for entire directories at once:
use Livewire\Blaze\Blaze;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Blaze::optimize()->in(resource_path('views/components'));
// ...
}
We recommend starting with specific directories, as your app may rely on features Blaze doesn't support. Gradually expand coverage and verify compatibility with known limitations.
Blaze::optimize()
->in(resource_path('views/components/button'))
->in(resource_path('views/components/modal'));
To exclude a subdirectory, use compile: false.
Blaze::optimize()
->in(resource_path('views/components'))
->in(resource_path('views/components/legacy'), compile: false);
You may also enable different optimization strategies per folder.
Blaze::optimize()
->in(resource_path('views/components/icons'), memo: true)
->in(resource_path('views/components/cards'), fold: true);
Component-level @blaze directives override directory-level settings.
Limitations
Blaze supports all essential features and produces HTML output identical to Blade. While the focus is on maximizing performance with full compatibility, there are some limitations to be aware of:
-
Class-based components are not supported
-
The
$componentvariable is not available -
View composers / creators / lifecycle events do not fire
-
Auto-injecting
View::share()variables is not supportedAccess shared data manually using
$__env->shared('key') -
Cross boundary
@awarebetween Blade and BlazeBoth parent and child must use Blaze for values to propagate
-
Rendering Blaze components using
view()will not workBlaze components can only be rendered using the component tag
Optimization Strategies
By default, Blaze uses the Function Compiler. It works for virtually all components and provides significant performance improvements — sufficient for most use cases.
For even greater gains, you may consider the advanced strategies below. These require additional thought and care.
| Strategy | Parameter | Default | Best For |
|----------|-----------|----------|----------|
| Function Compiler | compile | true | General use |
| Runtime Memoization | memo | false | Repeated components |
| Compile-Time Folding | fold | false | Maximum performance |
Function Compiler
This is the default behavior. It's a reliable optimization that requires no changes and can be safely applied to nearly all templates without concerns about stale data or dynamic content.
Rendering 25,000 anonymous components in a loop:
| Scenario | Blade | Blaze | Reduction | |----------|-------|-------|-----------| | No attributes | 500ms | 13ms | 97.4% | | Attributes only | 457ms | 26ms | 94.3% | | Attributes + merge() | 546ms | 44ms | 91.9% | | Props + attributes | 780ms | 40ms | 94.9% | | Default slot | 460ms | 22ms | 95.1% | | Named slots | 696ms | 49ms | 93.0% | | @aware (nested) | 1,787ms | 129ms | 92.8% |
These numbers reflect rendering pipeline overhead. If your templates perform expensive operations internally, that work will still affect performance.
How it works
When you enable Blaze, your templates are compiled into optimized PHP functions that skip the standard rendering pipeline while maintaining compatibility with Blade syntax.
@blaze
@props(['type' => 'button'])
<button {{ $attributes->merge(['type' => $type]) }}>
{{ $slot }}
</button>
Compiles to:
function _c4f8e2a1($__data, $__slots) {
$type = $__data['type'] ?? 'button';
$attributes = new BlazeAttributeBag($__data);
// ...
}
When you include the component, Blaze calls this function directly.
<x-button type="submit">Send</x-button>
Becomes:
_c4f8e2a1(['type' => 'submit'], ['default' => 'Send']);
Runtime Memoization
This strategy is ideal for icons, avatars, and other elements that frequently appear with the same props. When a memoized component appears multiple times on a page, it renders only once.
[!IMPORTANT] Memoization only works on components without slots.
How it works
The output is cached based on the component name and props passed to it.
@blaze(memo: true)
@props(['name'])
<x-dynamic-component :component="'icon-' . $name" />
When you include the component, Blaze wraps it in a cache check and only renders it the first time it's used with those props.
<x-icon :name="$task->status->icon" />
Becomes:
<?php $key = Memo::key('icon', ['name' => $task->status->icon]); ?>
<?php if (! Memo::has($key)): ?>
<!-- Render and store into cache: -->
<x-icon :name="$task->status->icon">
<?php endif; ?>
<?php echo Memo::get($key); ?>
Compile-Time Folding
Compile-time folding is Blaze's most aggressive optimization. The component ceases to exist at runtime — no function call, no variable resolution, no overhead whatsoever. Just the HTML.
Rendering time remains constant regardless of component count:
| Components | Blade | Blaze (folded) | |------------|-------|----------------| | 25,000 | 500ms | 0.68ms | | 50,000 | 1,000ms | 0.68ms | | 100,000 | 2,000ms | 0.68ms |
[!CAUTION] Folding requires careful consideration. Used incorrectly, it can cause subtle bugs that are difficult to diagnose. Make sure you fully understand how it works before enabling this strategy.
How It Works
Blaze pre-renders components during compilation, embedding the HTML directly into your template. This eliminates all runtime overhead, enabling exceptional performance gains. However, these gains come at a cost — folding requires a thorough understanding of its mechanics and careful consideration.
The following sections explore how folding works so you can use it safely.
Overview
The most important thing to understand is that folding produces static HTML. All internal logic, conditions, and dynamic content are baked in at compile time. This can create subtle bugs where a component works correctly in some places but breaks in others.
Blaze tries to avoid folding when it's likely to cause problems, but it cannot detect all cases. You'll need to analyze each component individually and configure when folding should be aborted.
Global state
Components that use global state should never be folded. This includes anything not passed in from the outside — data accessed via helper functions, facades, or Blade directives. Using any of these patterns inside the component will produce incorrect results when folded.
[!WARNING] Components that use global state must not be marked with
fold: true. Blaze attempts to detect global state usage and will throw an exception when it does, but it cannot catch everything.
| Category | Examples |
|----------|----------|
| Database | User::get() |
| Authentication | auth()->check(), @auth, @guest |
| Session | session('key') |
| Request | request()->path(), request()->is() |
| Validation | $errors->has(), $errors->first() |
| Time | now(), Carbon::now() |
| Security | @csrf |
This applies to internal logic. Passing global state into the component via attributes or slots can be fine — however, there are exceptions. We'll explore these in the following sections.
Static attributes
Let's explore the folding process with a simple example where everything works smoothly.
Consider a button component that dynamically resolves Tailwind classes based on the color prop.
@blaze(fold: true)
@props(['color'])
@php
$classes = match($color) {
'red' => 'bg-red-500 hover:bg-red-400',
'blue' => 'bg-blue-500 hover:bg-blue-400',
default => 'bg-gray-500 hover:bg-gray-400',
};
@endphp
<button {{ $attributes->class($classes) }}>
{{ $slot }}
</button>
When you include it with a static prop:
<x-button color="red">Submit</x-button>
Blaze renders the component and replaces it with static HTML during compilation:
<button class="
