Livewire Computed Properties: Derive State Without Bloating the Component Payload
Livewire computed properties let you derive data from existing state without serializing it into every request payload. Here's how they work, with a filtering example and verification steps.
12 Jul 2025, 16:40 UTC

The short answer
When a Livewire component needs data that can be calculated from state it already has — a filtered list, a total, a formatted label — don't store that data in a public property. Define it as a computed property instead. You get the value on demand in your Blade view, it is cached for the rest of that request, and it never travels in the JSON payload between browser and server.
Public properties in Livewire are serialized into every request and response. Anything you can derive from existing state is pure overhead in that payload. Computed properties are the mechanism for keeping derived data server-side only.
How the mechanism works
Livewire's public properties must survive the round trip: the component is dehydrated to JSON after each render and rehydrated on the next update. That means every public property adds weight to the snapshot sent to the browser and back.
A computed property is just a method on the component. Because it isn't stored as state, Livewire never serializes it. When your Blade template references it, Livewire calls the method, caches the result in memory for the remainder of that request, and returns the cached value on subsequent accesses within the same render cycle. The next request starts fresh, so the method runs again — which is exactly what you want for derived data.
A worked example: filtered search results
Assume Livewire v2 (the get...Property convention). The component holds only the raw inputs as public state:
class UserSearch extends Component
{
public $search = '';
public $onlyActive = false;
public function getResultsProperty()
{
return User::query()
->when($this->onlyActive, fn ($q) => $q->where('active', true))
->when($this->search, fn ($q) => $q->where('name', 'like', '%' . $this->search . '%'))
->limit(50)
->get();
}
public function render()
{
return view('livewire.user-search');
}
}
In the Blade view you access it like a normal property, and you can reference it more than once without paying for the query twice:
<div>
<input wire:model.debounce.300ms='search' type='text'>
<label><input wire:model='onlyActive' type='checkbox'> Active only</label>
<p>{{ $this->results->count() }} matches</p>
<ul>
@foreach ($this->results as $user)
<li>{{ $user->name }}</li>
@endforeach
</ul>
</div>
Here $this->results is referenced twice in one render, but the query executes once because of the per-request cache. If results had been a public property holding an Eloquent collection, Livewire would attempt to serialize that collection into every payload — slower, larger, and a common source of hydration bugs.
Version note: Livewire v3
In Livewire v3 the convention changed. Computed properties are declared with the [Computed] attribute on a plain method, and the per-request caching behavior is explicit:
use Livewire\Attributes\Computed;
#[Computed]
public function results()
{
return User::query()->where('name', 'like', '%' . $this->search . '%')->get();
}
Access it in Blade the same way ($this->results). Check which major version your project uses (composer show livewire/livewire) before copying either pattern — the v2 magic naming convention does not apply in v3.
Limits and common mistakes
- They run on every render. The cache lasts one request only. If the computed method does expensive work, every keystroke that triggers an update re-runs it. Keep computed logic cheap, or push heavy work behind an explicit action.
- They don't trigger re-renders themselves. A computed property is recalculated because something else changed — a public property update or an action call. If nothing else changes, nothing re-renders.
- Naming is strict in v2. The method must be
get+ StudlyCase name +Property. A method namedresults()orgetResults()is just a method; it won't be cached or accessible as$this->results. - Don't mutate state inside them. Because they may be called multiple times per request (before the cache fills) and on every render, side effects inside a computed property are unreliable and hard to debug.
- Not a substitute for pagination. Filtering a
limit(50)query is fine; returning thousands of rows to Blade is still slow regardless of where the query lives.
How to verify it's working
- Query count: Install Laravel Telescope or Clockwork, load the component, and confirm the query inside the computed method runs once per request even though the property is referenced multiple times in the view.
- Payload size: Open the browser's network tab, trigger an update, and inspect the Livewire request/response JSON. The computed value should appear only in the rendered HTML, not in the component's state snapshot. Compare against a version where the same data is a public property to see the difference.
If the query runs more than once per request, check that you're accessing the property ($this->results) rather than calling a method, and that the naming convention matches your Livewire version.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.