developing-with-turbo-streams
Implements Turbo Streams for real-time, partial page updates and dynamic content rendering.
Install
mkdir -p .claude/skills/developing-with-turbo-streams && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/3413" && unzip -o skill.zip -d .claude/skills/developing-with-turbo-streams && rm skill.zipInstalls to .claude/skills/developing-with-turbo-streams
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Basics of developing with Turbo Streams in web applications. Activate when working on projects that utilize Turbo Streams for enhancing user experience through real-time updates, dynamic content changes, and partial page updates without full reloads.Key capabilities
- →Constructs HTTP Turbo Stream response objects
- →Injects HTML snippets using DOM actions
- →Detects Turbo-specific request headers
- →Updates partial components without full page reloads
- →Synthesizes server-side model state into stream actions
How it works
Uses a fluent PHP builder to return standardized Turbo-encoded HTML responses that the browser-side Turbo Drive handles via event listeners.
Inputs & outputs
When to use developing-with-turbo-streams
- →Implementing real-time list updates
- →Updating page components without full reloads
- →Managing WebSocket broadcast actions
About this skill
Turbo Streams
Turbo Streams let you change any part of the page using eight actions: append, prepend, replace, update, remove, before, after, and refresh. They work as HTTP responses (after form submissions) and as real-time broadcasts over WebSocket.
HTTP Turbo Streams
Detecting Turbo Stream Requests
Check if the request accepts Turbo Stream responses before returning them:
@verbatim
<code-snippet name="Detecting" lang="php"> public function store(Request $request) { $post = Post::create($request->validated());if ($request->wantsTurboStream()) {
return turbo_stream($post);
}
return redirect()->route('posts.show', $post);
} </code-snippet>
@endverbatim
The turbo_stream() Helper
@verbatim
<code-snippet name="turbo_stream helper" lang="php"> // Auto-detect action from context (uses model state: created → append, updated → replace, deleted → remove) return turbo_stream($model); return turbo_stream($model, 'prepend');// Fluent builder (no arguments returns a PendingTurboStreamResponse) return turbo_stream()->append('posts', view('posts._post', ['post' => $post])); return turbo_stream()->prepend('posts', view('posts._post', ['post' => $post])); return turbo_stream()->before(dom_id($post), view('posts._post', ['post' => $newPost])); return turbo_stream()->after(dom_id($post), view('posts._post', ['post' => $newPost])); return turbo_stream()->replace($post, view('posts._post', ['post' => $post])); return turbo_stream()->update($post, view('posts._post', ['post' => $post])); return turbo_stream()->remove($post); return turbo_stream()->refresh(); </code-snippet>
@endverbatim
Targeting Multiple Elements
Use the *All methods or targets() to target multiple elements by CSS selector:
@verbatim
<code-snippet name="Multiple targets" lang="php"> return turbo_stream()->appendAll('.comment', view('comments._comment', ['comment' => $comment])); return turbo_stream()->replaceAll('.notification', view('notifications._notification')); return turbo_stream()->removeAll('.old-item'); </code-snippet>@endverbatim
Morph Method
Use morph() on replace/update to morph content instead of replacing it:
@verbatim
<code-snippet name="Morph" lang="php"> return turbo_stream()->replace($post, view('posts._post', ['post' => $post]))->morph(); </code-snippet>@endverbatim
Combining Multiple Streams
Pass an array or collection to return multiple stream actions in one response:
@verbatim
<code-snippet name="Multiple streams" lang="php"> return turbo_stream([ turbo_stream()->append('posts', view('posts._post', ['post' => $post])), turbo_stream()->update('post_count', view('posts._count', ['count' => Post::count()])), turbo_stream()->remove('empty_state'), ]); </code-snippet>@endverbatim
Turbo Stream Views
Render a full Blade view with the Turbo Stream content type. Useful for complex multi-stream responses:
@verbatim
<code-snippet name="Stream view" lang="php"> return turbo_stream_view('posts.turbo.created', ['post' => $post]); </code-snippet> <code-snippet name="Stream view template" lang="blade"> {{-- resources/views/posts/turbo/created.blade.php --}} <x-turbo::stream action="append" target="posts"> @include('posts._post', ['post' => $post]) </x-turbo::stream><x-turbo::stream action="update" target="post_count"> {{ Post::count() }} posts </x-turbo::stream> </code-snippet>
@endverbatim
The Stream Blade Component
@verbatim
<code-snippet name="Blade component" lang="blade"> {{-- Single target by ID --}} <x-turbo::stream action="append" target="messages"> <div id="message_1">My new message!</div> </x-turbo::stream>{{-- Target by model (auto-generates DOM ID) --}} <x-turbo::stream action="replace" :target="$post"> @include('posts._post', ['post' => $post]) </x-turbo::stream>
{{-- Multiple targets by CSS selector --}} <x-turbo::stream action="remove" targets=".notification" /> </code-snippet>
@endverbatim
Broadcasting (Real-Time Streams)
The Broadcasts Trait
Add the Broadcasts trait to your Eloquent model:
@verbatim
<code-snippet name="Broadcasts trait" lang="php"> use HotwiredLaravel\TurboLaravel\Models\Broadcasts;class Post extends Model { use Broadcasts; } </code-snippet>
@endverbatim
Manual Broadcasting
Call broadcast methods directly on a model instance:
@verbatim
<code-snippet name="Manual broadcasting" lang="php"> $comment->broadcastAppend(); $comment->broadcastPrepend(); $comment->broadcastReplace(); $comment->broadcastUpdate(); $comment->broadcastRemove(); $comment->broadcastBefore('some_target'); $comment->broadcastAfter('some_target'); $comment->broadcastRefresh();// Broadcast only to other users (exclude current user) $comment->broadcastAppend()->toOthers();
// Queue the broadcast for async processing $comment->broadcastAppend()->later(); </code-snippet>
@endverbatim
Directed Broadcasting
Broadcast to a specific model's channel:
@verbatim
<code-snippet name="Directed broadcasting" lang="php"> // Broadcast to the post's channel instead of the comment's own channel $comment->broadcastAppendTo($post); $comment->broadcastPrependTo($post); $comment->broadcastReplaceTo($post); $comment->broadcastUpdateTo($post); $comment->broadcastRemoveTo($post); $comment->broadcastRefreshTo($post); </code-snippet>@endverbatim
Automatic Broadcasting
Enable automatic broadcasts on model lifecycle events:
@verbatim
<code-snippet name="Auto broadcasting" lang="php"> class Comment extends Model { use Broadcasts;// Enable auto-broadcasting (broadcasts on create, update, delete)
protected $broadcasts = true;
// Customize insert action (default is 'append')
protected $broadcasts = ['insertsBy' => 'prepend'];
// Specify which model's channel to broadcast to
protected $broadcastsTo = 'post';
// Or define dynamically
public function broadcastsTo()
{
return $this->post;
}
} </code-snippet>
@endverbatim
Page Refresh Broadcasting
Instead of granular stream actions, broadcast a page refresh signal:
@verbatim
<code-snippet name="Refresh broadcasting" lang="php"> class Post extends Model { use Broadcasts;// Auto-broadcast page refreshes on model changes
protected $broadcastsRefreshes = true;
} </code-snippet>
@endverbatim
This works best with <x-turbo::refreshes-with method="morph" scroll="preserve" /> in the layout.
Listening for Broadcasts
Use the <x-turbo::stream-from> component in your Blade views to subscribe to a channel:
@verbatim
<code-snippet name="Listening" lang="blade"> {{-- Private channel (default) — requires channel auth --}} <x-turbo::stream-from :source="$post" />{{-- Public channel — no auth needed --}} <x-turbo::stream-from :source="$post" type="public" /> </code-snippet>
@endverbatim
Define the channel authorization in routes/channels.php:
@verbatim
<code-snippet name="Channel auth" lang="php"> use App\Models\Post;Broadcast::channel(Post::class, function ($user, Post $post) { return $user->belongsToTeam($post->team); }); </code-snippet>
@endverbatim
Handmade Broadcasts (via Facade)
Use the TurboStream facade for broadcasts not tied to a model:
@verbatim
<code-snippet name="Facade broadcasting" lang="php"> use HotwiredLaravel\TurboLaravel\Facades\TurboStream;TurboStream::broadcastAppend( content: view('notifications._notification', ['notification' => $notification]), target: 'notifications', channel: 'general', );
TurboStream::broadcastRemove(target: 'notification_1', channel: 'general'); TurboStream::broadcastRefresh(channel: 'general'); </code-snippet>
@endverbatim
Broadcasting from Response Builder
Chain broadcastTo() on a Turbo Stream response to also broadcast it:
@verbatim
<code-snippet name="Response broadcasting" lang="php"> turbo_stream() ->append('posts', view('posts._post', ['post' => $post])) ->broadcastTo('general'); </code-snippet>@endverbatim
Global Broadcast Scope
Exclude the current user from all broadcasts in a request:
@verbatim
<code-snippet name="Broadcast to others" lang="php"> use HotwiredLaravel\TurboLaravel\Facades\Turbo;// In a controller or middleware Turbo::broadcastToOthers();
// Anywhere Turbo::broadcastToOthers(function () { // Turbo Streams broadcasted here will not be delivered to the current user... }); </code-snippet>
@endverbatim
When not to use it
- →Standard non-AJAX full page navigation
- →Client-side heavy applications avoiding server-rendered HTML
Prerequisites
Limitations
- →Requires server-side HTML rendering
- →Limited to eight specific DOM actions
How it compares
Eliminates custom JavaScript boilerplate for common DOM manipulation tasks like appending list items or replacing error blocks.
Compared to similar skills
developing-with-turbo-streams side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| developing-with-turbo-streams (this skill) | 1 | 5mo | No flags | Intermediate |
| laravel-specialist | 12 | 3mo | No flags | Intermediate |
| developing-with-turbo-basics | 1 | 5mo | No flags | Intermediate |
| payment-integration | 1 | 6mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by hotwired-laravel
View all by hotwired-laravel →You might also like
laravel-specialist
Jeffallan
Use when building Laravel 10+ applications requiring Eloquent ORM, API resources, or queue systems. Invoke for Laravel models, Livewire components, Sanctum authentication, Horizon queues.
developing-with-turbo-basics
hotwired-laravel
Basics of developing with Turbo in web applications. Activate when working on projects that utilize Turbo for enhancing user experience through partial page updates, real-time interactions, and seamless navigation without full page reloads.
payment-integration
mrgoonie
Integrate payments with SePay (VietQR), Polar, Stripe, Paddle (MoR subscriptions), Creem.io (licensing). Checkout, webhooks, subscriptions, QR codes, multi-provider orders.
developing-with-prism
prism-php
Guide for developing with Prism PHP package - a Laravel package for integrating LLMs. Activate or use when working with Prism features including text generation, structured output, embeddings, image generation, audio processing, streaming, tools/function calling, or any LLM provider integration (OpenAI, Anthropic, Gemini, Mistral, Groq, XAI, DeepSeek, OpenRouter, Ollama, VoyageAI, ElevenLabs). Activate for any Prism-related development tasks.
laravel-query-builder
relaticle
Build filtered, sorted, and included API endpoints using spatie/laravel-query-builder. Activates when working with QueryBuilder, AllowedFilter, AllowedSort, AllowedInclude, or when the user mentions query parameters, API filtering, sorting, includes, or spatie/laravel-query-builder.
echo-development
WageFolabessy
Develops real-time broadcasting with Laravel Echo. Activates when setting up broadcasting (Reverb, Pusher, Ably); creating ShouldBroadcast events; defining broadcast channels (public, private, presence, encrypted); authorizing channels; configuring Echo; listening for events; implementing client eve