# TwigBridge lets a Laravel application render .twig views

> TwigBridge is a Composer package that gives Laravel applications the Twig templating engine, so a .twig file in resources/views is rendered like any other view, with Laravel's helpers, facades and form builders exposed to templates. The trade is that you now have two template languages in one application, and the package has to keep the bridge between them in step with both.

**rcrowe/TwigBridge** — Give the power of Twig to Laravel

- Repository: https://github.com/rcrowe/TwigBridge
- Stars: 904 · Forks: 170
- Language: PHP
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/rcrowe-twigbridge

## A second template engine inside a framework that already has one

TwigBridge allows you to use Twig seamlessly in Laravel, and the project description puts it plainly: give the power of Twig to Laravel.

The audience is narrower than it might look. Laravel ships Blade, and Blade is good, so nobody installs this package to replace Blade with something they have never used. The people who install TwigBridge fall into two groups. The first is a developer with an existing Twig codebase, a site built on Symfony years ago perhaps, that now has to live inside a Laravel application and keep its templates. The second is a team that has decided Twig is the better template language and wants it inside Laravel on its own terms, accepting that the framework's conventions will be expressed as Twig functions and filters rather than as Blade directives.

That second group is where the interesting design work is, and the README is mostly about it. Laravel exposes a great deal through PHP helpers and facades, the things you would use in a Blade template as directives, and Twig has no concept of them. TwigBridge's job is to make those available inside a Twig template, either as functions, as filters, or as callable facades, and to keep that mapping in one configurable place.

The package is MIT licensed, the primary language is PHP, and the default branch is master. The repository layout is compact and conventional for a Composer package: src/ for the code, config/ for the configuration file that gets published, tests/ with a phpunit.xml, a composer.json, a CHANGELOG.md and an UPGRADE.md.

## Two commands get you from nothing to a rendered .twig view

The installation is a Composer require, and then a decision about configuration.

```bash
composer require rcrowe/twigbridge
```

Laravel automatically registers the service provider, so there is nothing to add to config/app.php on a modern application. The one step that remains is publishing the Twig configuration file with Artisan:

```bash
php artisan vendor:publish --provider="TwigBridge\ServiceProvider"
```

After that you write a template with the .twig extension in resources/views, and the README's example is deliberately trivial:

```html
<!-- resources/views/welcome.twig -->
<h1>
  Welcome to TwigBridge!
</h1>
```

And you return it from a route like any other view:

```php
// routes/web.php

use Illuminate\Support\Facades\Route;

Route::get('/', static function () {
    return view('welcome');
});
```

That is the whole quick start, and the point of it is that a Twig view is not a special case. The view resolver finds welcome.twig, the bridge renders it through the Twig environment, and the route code is identical to the Blade version. The extension is what makes it invisible.

One thing to know about the publishing step, because it surprises people. The default configuration file lives in the vendor directory, at vendor/rcrowe/twigbridge/config, and the Artisan command copies it to /config/twigbridge.php in your application. You are meant to edit the copy, and the README says the configuration can be extended in your ConfigServiceProvider under the twigbridge key. The default file is also where the list of enabled extensions lives, which is the next thing to look at.

## Auto-discovery, manual registration and the Lumen variant

The registration story depends on the Laravel version, and the README splits it in two.

For modern Laravel, 5.5 and above, the service provider and the facade are registered automatically through Package Auto-Discovery. Manual registration in config/app.php is not required, and the README says you can skip straight to publishing the configuration file.

For legacy Laravel, 5.4 and below, which has no Package Auto-Discovery support, you register the provider yourself. Open config/app.php, find the providers key towards the bottom and add:

```php
'TwigBridge\ServiceProvider',
```

The facade is optional and gives easier access to TwigBridge or the Twig environment itself:

```php
'Twig' => 'TwigBridge\Facade\Twig',
```

and with it you can register extensions and render templates directly:

```php
Twig::addExtension('TwigBridge\Extension\Loader\Functions');
Twig::render('mytemplate', $data);
```

Lumen is a third case, and it needs more work. You load the same service provider, but you have to disable the Auth, Translator and Url extensions in your local configuration, because Lumen does not include those services by default and the bridge's extensions expect them. You copy the config/twigbridge.php file into your local config folder and register both the configuration and the provider in bootstrap/app.php:

```php
$app->configure('twigbridge');
$app->register('TwigBridge\ServiceProvider');
```

That last detail is the most informative thing in this section. The default extension set assumes Auth, Translator and Url are present, and on Lumen you have to turn them off rather than have them fail at runtime. The bridge is opinionated about the framework it plugs into, which is reasonable, but it does mean the package is not a drop in for every Laravel flavour.

## Package views and template inheritance keep working

One of the more valuable capabilities is that Twig templates can use views published by other packages, which is what makes TwigBridge useful in a real application rather than a demo.

You call a template the same way you would call one of your own, with the package prefix syntax and without the file extension:

```php
View::make('pagination::simple')
```

That is a package view, and the same rules apply when you extend a template rather than rendering one. The extends tag names the parent, and the parent can equally be a package template:

```html
{% extends "parent" %}
{% extends "pagination::parent" %}
```

So a Twig template in your application can inherit from a template that a vendor package published, which means the whole Laravel ecosystem of view packages stays reachable from Twig code rather than only from Blade.

The template syntax itself carries the Laravel helpers as functions. The README shows a call with parameters, a route helper with a URL generator and a set of attributes:

```html
{{ link_to_route('tasks.edit', 'Edit', task.id, {'class': 'btn btn-primary'}) }}
```

And output is escaped by default, which is the behaviour you want from a template engine, with the raw filter available when you deliberately want to skip escaping, alongside the string helpers:

```html
{{ some_var }}
{{ html_var | raw }}
{{ long_var | str_limit(50) }}
```

The default escaping is worth a sentence on its own, because it is the sort of default that decides whether a template layer is safe. A Twig template that escapes by default does not need the same care as one that does not, and the raw filter is an explicit, visible opt out rather than the default.

## The default extensions are what turn Twig into Laravel

The extension list is the mechanism, and the README enumerates it.

The enabled by default set includes the Twig debug extension, and a set of TwigBridge extensions that expose Laravel's own services to templates: Auth, Config, Dump, Form, Gate, Html, Input, Session, String, Translator and Url, plus three loader extensions for Facades, Filters and Functions.

Each of those exposes a family of helpers. The functions list in the README shows the shape of it: asset, action, url, route, secure_url and secure_asset; auth_check, auth_guest and auth_user; can; config_get and config_has; dump; form_* covering all the Form methods snake cased; html_* covering the Html methods; input_get, input_old and input_has; link_to, link_to_asset, link_to_route and link_to_action; session_has, session_get, csrf_token, csrf_field and method_field; str_* covering the Str methods; trans and trans_choice; and url_* covering the URL methods. The filters list starts with the string case helpers, camel_case, snake_case and studly.

That is the whole surface area of the bridge, and it is where the value sits. Rather than trying to map Laravel onto Twig's own idioms, the package exposes Laravel's API unchanged, snake cased, so a template author who knows Laravel can use it.

Adding your own extension is a config change, and the enabled array in config/twigbridge.php is where it goes. The value can be a class name:

```php
'enabled' => array(
    'TwigBridge\Extensions\Example'
)
```

or a closure, and the README gives the Assetic extension as the worked example of the closure form, where the closure receives the application and returns the extension instance. That closure form is what makes it possible to add an extension that needs the container, rather than only the ones that are constructed from nothing.

## Config changes need twig:clean, and that is the sharp edge

There is one operational detail in the README that will save you an afternoon, and it is easy to skim past.

The default configuration file can be extended in your ConfigServiceProvider under the twigbridge key, and the default file itself is at vendor/rcrowe/twigbridge/config. You are expected to copy it to /config/twigbridge.php with the Artisan publish command rather than editing the vendor copy. The README then says that if you make changes to the /config/twigbridge.php file, you will most likely have to run the twig:clean Artisan command for the changes to take effect.

The mechanism behind that is the compiled template cache. Twig compiles a template to PHP and caches the result, and the cache key does not change when you change which extensions are loaded, because the template source has not changed. So the extension list changes, the cache does not invalidate, and your new function is missing. The clean command forces the cache to be rebuilt.

The same file also holds the facade configuration, since the FacadeLoader extension allows you to call any facade you have configured in config/twigbridge.php, and that is what gives templates integration with any Laravel class as well as any other classes you alias. The README describes calling them like URL.to(link) instead of URL::to($link).

The practical lesson for an integrator is that config changes in this package are not always picked up by a cache clear, and the specific command to run is twig:clean. The README does not document what that command removes or whether it affects the whole application, so treat it as the documented step and verify the effect in your own environment.

## Twig 3 since 0.13, and a 0.x line with a long tail

The requirements section is one sentence and it decides your version: TwigBridge 0.13 and above supports Twig 3, and if you need Twig 1 or 2 support you use the 0.12 versions.

That is a hard fork in the road for anyone arriving from an older codebase. The 0.12 line is where the older Twig generations live, and it is no longer the line that receives work, since the recent releases are all in the 0.14 range. The most recent tags are v0.14.8 on 2026-10-16, v0.14.7 on 2026-03-20 and v0.14.6 on 2025-08-25, and the last push was on 2026-10-16, so the 0.14 line is where the activity is.

The 0.x version number is the other thing to note. The project has not committed to a 1.0, and in a package that reaches into the framework's service container and registers a dozen extensions, a major version bump is the kind of event that can change behaviour for a downstream application without anyone calling it a breaking change in the changelog. The UPGRADE.md file at the repository root is where to look before moving between lines, and the CHANGELOG.md records the per version changes.

The licence is MIT, with the LICENSE file at the repository root, which is the permissive choice you would want for a package that is installed into an application rather than shipped as a product.

For a team, the sensible pattern is to pin a 0.14.x release, read the changelog before each upgrade, and treat the jump from the 0.12 line to the 0.13 and later lines as a migration with its own work, since it carries the Twig 2 to Twig 3 change as well as the package's own evolution.

## Conclusion

Adopt TwigBridge if you are building a Laravel application whose templates are written in Twig, or if you are porting an existing Twig codebase onto Laravel and want the framework helpers available inside those templates, and if you can live with two template languages in the same project. Do not adopt it to try Twig out in a Blade application, since the package installs a whole engine and a configuration file to maintain for what Blade already does. Before you commit, check the version requirement, because 0.13 and above target Twig 3 while 0.12 is the line for Twig 1 and 2, read UPGRADE.md, and remember that changes to config/twigbridge.php need the twig:clean Artisan command to take effect.

## FAQ

### What does TwigBridge do in a Laravel application?

It lets you use Twig in Laravel, so a file with the .twig extension in resources/views is rendered like any other view. The package supplies a service provider, a configuration file and a set of extensions that expose Laravel's helpers and facades to Twig templates.

### How do I install TwigBridge and publish its configuration?

Run composer require rcrowe/twigbridge, then publish the configuration with php artisan vendor:publish --provider="TwigBridge\ServiceProvider". On Laravel 5.5 and above the service provider registers automatically through Package Auto-Discovery.

### Which Twig versions does TwigBridge support?

TwigBridge 0.13 and above supports Twig 3, and the 0.12 versions are the ones to use for Twig 1 and 2 support. The recent releases are all on the 0.14 line, v0.14.8 being the newest.

### Why are my TwigBridge configuration changes ignored?

The README says that if you make changes to the config/twigbridge.php file you will most likely have to run the twig:clean Artisan command for the changes to take effect, because the compiled template cache is not invalidated by a change to the extension list.

### Can a Twig template use a view published by another package?

Yes. The same rules continue when extending another Twig template, so you can call a package view with View::make('pagination::simple') and extend a package template with {% extends "pagination::parent" %}.

## Sources

- [Issues](https://github.com/rcrowe/TwigBridge/issues)
- [License: MIT](https://github.com/rcrowe/TwigBridge/blob/master/LICENSE)
- [rcrowe/TwigBridge on GitHub](https://github.com/rcrowe/TwigBridge)
- [README](https://github.com/rcrowe/TwigBridge/blob/master/README.md)
- [Releases](https://github.com/rcrowe/TwigBridge/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rcrowe-twigbridge
