@forelse
Loops over an iterable and renders an alternative block when it yields no items.
@forelse ($array as $value) ... @empty ... @endforelseParameters
| Parameter | Type | Description |
|---|---|---|
$array | iterable | The array, Collection or Traversable to walk, written as the full PHP foreach expression including the `as` clause. |
$value | mixed | The variable bound to the current element inside the loop body. |
Return value
Nothing — either the loop body once per element, or the @empty block when the iterable produced no elements.
Errors
Closing the block with @endforeach instead of @endforelse leaves the compiled PHP unbalanced and raises a ParseError in the cached view.
@forelse is @foreach with an empty state built in. Blade sets a flag before the loop and clears it on the first iteration, so the @empty branch renders exactly when the body never ran. That detail matters: the decision is made by the loop itself, not by calling count(), so generators and lazy collections that turn out to be empty still take the branch.
When to reach for it
Any list that can legitimately be empty — search results, a notifications dropdown, an order history — should be a @forelse. It replaces the @if (count($x)) ... @else ... @endif wrapper around a @foreach, which is easy to get subtly wrong when the value is a Collection rather than an array.
What trips people up
The @empty that separates the branches takes no argument. It is spelled the same as the standalone @empty($var) ... @endempty conditional, and writing @empty($users) inside a @forelse opens a nested block that never closes.
The $loop variable is available in the body just as it is in @foreach, including first, last, count and parent.
Example
<?php
use Illuminate\Support\Facades\Blade;
$template = <<<'BLADE'
<ul>
@forelse ($users as $user)
<li>{{ $user }}</li>
@empty
<li>No users</li>
@endforelse
</ul>
BLADE;
echo Blade::render($template, ['users' => []]);
// <ul>
// <li>No users</li>
// </ul>
echo Blade::render($template, ['users' => ['Ada', 'Grace']]);
// <ul>
// <li>Ada</li>
// <li>Grace</li>
// </ul>When to use it
- Show 'No results for that search' instead of an empty table body
- Render a notifications dropdown with a friendly placeholder when nothing is unread
- List a customer's past orders and invite them to place their first one when there are none
Frequently asked questions
What is the difference between @forelse and @foreach in Blade?
@forelse adds an @empty branch that renders when the iterable produced no items, so you do not need to wrap a @foreach in a conditional. Otherwise it behaves identically, including the $loop variable.
Does @empty inside @forelse take an argument?
No. Inside @forelse, @empty is a branch marker written on its own with no parentheses and no @endempty. The standalone @empty($var) ... @endempty conditional is a different directive that happens to share the name.
Can I use $loop inside a @forelse block?
Yes — the loop body gets the same $loop object as @foreach, with index, iteration, count, first, last, depth and parent. The @empty branch runs outside the loop, so $loop is not defined there.
More examples
A search results table with $loop
The empty branch keeps the table structurally valid — a browser given an empty <tbody> renders a collapsed table, which is why an empty state usually has to be a row rather than nothing at all. $loop works in the body exactly as it does in @foreach, so numbering the results costs nothing extra.
<?php
// resources/views/search/results.blade.php
$view = <<<'BLADE'
<table>
<tbody>
@forelse ($results as $result)
<tr>
<td>{{ $loop->iteration }}</td>
<td>{{ $result->title }}</td>
</tr>
@empty
<tr>
<td colspan="2">No results for "{{ $query }}".</td>
</tr>
@endforelse
</tbody>
</table>
BLADE;
echo view('search.results', [
'results' => $results,
'query' => request('q'),
])->render();The mistake that breaks the block
The first version is parsed as the standalone @empty($users) conditional opening a new block, so Blade never sees the forelse empty branch and @endforelse closes the wrong construct. The failure appears as a ParseError in storage/framework/views naming a line you did not write, which is why this typo costs more time than it should.
<?php
// Wrong: @empty inside @forelse must not take an argument.
$broken = <<<'BLADE'
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty($users)
<li>No users</li>
@endforelse
BLADE;
// Right:
$fixed = <<<'BLADE'
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
<li>No users</li>
@endforelse
BLADE;
echo $fixed;Replacing the manual wrapper
Both render the same output, but the verbose form has to pick the right emptiness test for the type it was handed — isNotEmpty() for a Collection, count() for an array, and neither for a generator. @forelse decides from whether the loop body executed, so it is correct for all three.
<?php
use Illuminate\Support\Facades\Blade;
// The pattern @forelse replaces.
$verbose = <<<'BLADE'
@if ($tags->isNotEmpty())
@foreach ($tags as $tag)
<span>{{ $tag }}</span>
@endforeach
@else
<span>Untagged</span>
@endif
BLADE;
$concise = <<<'BLADE'
@forelse ($tags as $tag)
<span>{{ $tag }}</span>
@empty
<span>Untagged</span>
@endforelse
BLADE;
echo Blade::render($concise, ['tags' => collect()]);
// <span>Untagged</span>
Discussion