symfony/ux-turbo
Symfony UX Turbo integrates Hotwire Turbo into Symfony apps so you get single-page-app speed and feel without writing JavaScript. It also works with Mercure to broadcast DOM updates to all connected users in real time.
turbo_stream_from(), keeping the real-time path aligned with current Mercure deployments.<twig:Turbo:Stream>, <twig:Turbo:Frame>) and functions (turbo_stream_from(), turbo_is_frame_request()), aligning with Symfony’s templating philosophy.data-turbo-* attributes to HTML elements). Ideal for teams with stronger PHP than JavaScript expertise.symfony/mercure-bundle ^0.6+ and Mercure ^0.9 (updated in v3.6.0; previously ^0.4.1+). This also unlocks Mercure protocol 1.0 support. It remains an additional moving part but enables powerful use cases like live notifications.TurboStreamListenRendererInterface). Teams using older Symfony UX packages (e.g., symfony/ux-turbo-mercure) must migrate to mercure-bundle. v3.6.0 improves this: the TurboStreamListenRenderer deprecation is now only triggered when the service is actually used, reducing noisy upgrade warnings and making deprecation triage safer.type: module in package.json), which may require adjustments to existing asset pipelines or browser support considerations.data-turbo="false").symfony/asset-mapper 8.2+; v3.6.0 resolves this conflict, reducing integration risk for projects on the modern asset mapper pipeline.Symfony Version Compatibility:
turbo_stream_listen()) in existing code? (Note: v3.6.0 only raises the TurboStreamListenRenderer deprecation when the service is used, so unused references will no longer pollute logs.)Frontend Strategy:
type: module) for Turbo’s JS, or can we use a CDN?Real-Time Requirements:
symfony/mercure-bundle ^0.6+ / Mercure ^0.9, or does upgrading affect our Mercure hub/protocol configuration? (Protocol 1.0 is now supported in turbo_stream_from().)Performance:
Team Skills:
data-turbo-* attributes)?Fallbacks:
Long-Term Maintenance:
@Broadcast attribute).Assessment Phase:
Setup:
composer require symfony/ux-turbo symfony/mercure-bundle:^0.6 # if needed
symfony/ux-turbo in config/bundles.php:
Symfony\UX\Turbo\TurboBundle::class => ['all' => true],
Symfony\UX\MercureBundle\MercureBundle::class => ['all' => true],
assets/controllers.json to enable the mercure-turbo-stream controller (if using Mercure).Incremental Adoption:
<turbo-frame> tags.<turbo-frame id="user_profile">
{% include 'user/profile.html.twig' %}
</turbo-frame>
TurboStreamResponse:
use Symfony\UX\Turbo\TurboBundle;
public function updateProfile(Request $request): Response
{
// ... update logic
if (TurboBundle::STREAM_FORMAT === $request->getPreferredFormat()) {
return $this->render('user/_profile.stream.html.twig', ['user' => $user]);
}
return $this->render('user/profile.html.twig', ['user' => $user]);
}
data-turbo attributes to links/forms:
<a href="/posts/1" data-turbo="true">View Post</a>
<form data-turbo="true">...</form>
<turbo-mercure-stream-source src="{{ path('mercure') }}" topics="{{ mercureHubUrl }}topic/posts">
@Broadcast:
#[Broadcast]
class Post {}
Testing:
Accept: text/vnd.turbo-stream.html.data-turbo="false").turbo_stream_from() against your Mercure hub protocol (1.0 now supported).symfony/asset-mapper 8.2+, making it compatible with the latest asset management pipeline.symfony/mercure-bundle ^0.6+ and Mercure ^0.9 for real-time features. Supports Mercure protocol 1.0 in turbo_stream_from().symfony/ux-turbo-mercure to mercure-bundle (if applicable).mercure-bundle ^0.6 / Mercure ^0.9 and confirm protocol 1.0 support with your hub.symfony/ux-turbo and configure bundles.TurboStreamListenRenderer now that they only fire on service use.TurboStreamListenRenderer deprecation notices to actual service usage, reducing log noise and false-positive maintenance tickets.mercure-bundle ^0.6, Mercure ^0.9, protocol 1.0) should be monitored as they evolve; plan periodic minor upgrades.data-turbo-*, Twig components), which are easier to onboard than full SPA state management.data-turbo="false" and no-JS clients.ux-turbo and mercure-bundle / mercure hub protocol can break live updates; pin composer constraints and validate in staging.asset-mapper 8.2+ existed; now resolved, but asset pipeline changes should still be regression-tested.TurboStreamListenRenderer usage still surfaces warnings when the service is actually invoked—treat these as planned cleanup work, not incidents.How can I help you explore Laravel packages today?