Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Twigbridge Laravel Package

barryvdh/laravel-twigbridge

TwigBridge lets you use the Twig templating engine in Laravel alongside Blade. It provides Twig extensions for Laravel helpers, facades, and auth, plus view integration so you can render .twig templates with familiar syntax and caching support.

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing to understand is that this bridge is a view-layer adapter, not a new framework. Nothing about controllers, routing, or models changes: you still call View::make('hello') and Laravel's view finder resolves hello.twig instead of hello.blade.php. That mental model — same Laravel, different file extension — is the whole package.

Minimal steps to a first rendering .twig template on a legacy Laravel 4 app:

  1. Pin the dependency. Add the package at an exact version in composer.json, and lock PHP in the platform config so an accidental composer update cannot resolve an incompatible Twig. This is not optional on an archived package.
  2. Register the provider. Add Barryvdh\TwigBridge\TwigServiceProvider to the providers array in app/config/app.php.
  3. Publish the config. Run php artisan config:publish barryvdh/laravel-twigbridge to materialize the config file with twig.paths, twig.options (cache, debug, auto_reload), the extensions array, and the functions/filters maps.
  4. Confirm the resolved Twig major. Run composer show twig/twig. This package targets Twig 1.x, and that single fact governs every extension you write — Twig_Extension and the filter/function signatures changed in Twig 2/3.
  5. Create a .twig file and render it through a normal controller action, verifying that at least one helper works: {{ asset('...') }}, {{ url('...') }}, {{ trans('...') }}, {{ csrf_field() }}.

Where to look first: the published config file. Everything a developer will touch day-to-day — paths, cache settings, which extensions are registered, which global functions/filters are exposed — lives there. Read it before writing a single template.

First use case: the trivial one — render an existing controller's view as .twig with the Blade helpers you already rely on. If {{ asset() }}, {{ url() }}, and {{ trans() }} all resolve and shared data + view-composer data appear as expected, the bridge is wired correctly and you can scale out template-by-template.

Implementation Patterns

Treat the bridge as a replaceable seam. The architecture supports this: it touches rendering only, owns no routing/persistence/business logic, and can be swapped without rewriting controllers. Keep your templates boring — no logic that belongs in a controller or a composer — so that a future collapse to Blade or upgrade path is a syntax translation, not a rewrite.

Render through the standard view path. Do not reach for the Twig environment directly in application code. Use View::make(), View::share(), and view composers as you would with Blade. The bridge back-fills composers, shared data, and translations into the Twig environment, so the Laravel idioms you already know are the correct ones.

Prefer extension classes over config closures. The config file supports registering helpers and extensions as closures, and that is fine for a spike. For anything that ships, register a proper Twig_Extension class in a service provider. Config closures do not survive config caching cleanly, and this is exactly the kind of thing that bites during a deploy when the compiled config differs from what you tested.

Build a helper-shim layer deliberately. This is the most important day-to-day pattern. The bridge exposes Laravel helpers, but Blade directives have no equivalent — there is no @csrf, @auth, @can, or @error. You must reconstruct those as Twig functions, as controller-passed booleans, or as tests. Decide once, write it down, and expose a consistent set of Twig functions (e.g. a can() function, an auth_user() global) so templates do not each reinvent authorization logic. This is where a silent regression becomes a security issue rather than a cosmetic one.

Escape by default, |raw by exception. Autoescaping is on. Helper output that contains HTML — a rendered CSRF field is the canonical case — needs |raw on trusted data only. Establish a team rule: |raw is allowed only on output you generated yourself (form fields, known-safe helpers), never on user or database content.

Keep Blade and Twig files separate. A file is parsed by exactly one engine, so there is no mixing syntax inside a template. This makes incremental migration practical: convert one view at a time, keep both extensions live, and never try to @include Blade from Twig or vice versa.

Warm the cache at deploy. Twig compiles to disk. Add a deploy step that renders representative pages (or otherwise primes the compiled views) so the first real request does not pay compilation cost. Clear app/storage/views whenever extensions or config change.

Sequence migration in countable units. Custom extensions, macros, config-registered closures, and globals are the migration work items — not lines of code. Config-closure helpers are the cheapest to port; bespoke Twig_Extension classes with tests are the most expensive. Inventory them early so estimates are based on counts.

Gotchas and Tips

Stale compiled templates are the routine failure mode. Blank pages, ghost output, or "function not found" after a config or extension change almost always means the compiled cache is out of sync. First debugging step, every time: clear the compiled views directory and clear Laravel's config cache, then retry. Errors surface at Twig line numbers rather than PHP lines — helpful — but stack traces route through compiled PHP in storage, so include the compiled file path in your debugging notes.

Watch the Twig 1.x constraint like a hawk. Any custom extension you write is written against Twig 1.x APIs. If someone adds a dependency that pulls Twig 2/3, extensions break and signatures shift. Pin twig/twig explicitly and set a platform PHP constraint in composer.json so resolution cannot drift.

Escaping regressions cut both ways. Double-escaped output is annoying; unescaped output is a vulnerability. Audit any |raw in the codebase as part of onboarding. If helpers render blank or mangled, the fix is usually an escaping decision, not a broken helper.

Assume no directive parity. Teammates coming from Blade will assume @csrf, @can, @auth, @error work. They do not. Document the shim layer and put authorization checks in a place where their absence fails loudly — tests, controller booleans — not silently in a template.

Do not lean on the Twig facade for boot-time globals without verification. Globals registered at boot and behaviors around them are the least documented part of the surface. Verify each one explicitly in a spike before relying on it.

Extension points worth knowing: the extensions array in config (for Twig extensions), the functions/filters maps (for quick helpers), the Twig facade (for runtime environment access), and view composers/shared data (for passing data the Laravel way). Prefer the last two in application code and the first two for infrastructure.

Own the fork. With the repo archived, there is no upstream to file issues against. Fork it, pin the commit, add it to dependency scanning, and name an owner. Keep a short internal runbook: dependency pinning rules, cache-clear procedure, the list of exposed helpers and custom extensions, and the cache-warm-up deploy step. Without it, knowledge of this package lives in one person's head.

Keep .twig and Blade side by side during migration and treat each converted template as a unit of progress. Do not attempt to mix syntax within a template — it will not parse.

Do not do performance work on this stack. Twig's compile-to-disk cache with opcache handles typical rendering workloads fine; the real constraint is Laravel 4's runtime and its inability to receive fixes. Treat optimization here as sunk cost unless the app is staying long-term — and if it is, budget the migration instead.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource