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

Pug Laravel Package

pug-php/pug

Pug-php/pug brings the Pug (formerly Jade) template engine to PHP. Write clean, indentation-based templates that compile to HTML, with Laravel integration, caching, and a concise syntax for faster, more readable views.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install the package. There is no official Laravel service provider bundled, so you wire it up yourself:

composer require pug-php/pug

2. Install the underlying Node compiler. pug-php/pug shells out to the real pug package via Node, so the runtime host needs both:

node -v                 # must exist
npm install -g pug      # or a local node_modules/pug in the project

Verify with pug --version. If pug is not on PATH, point the package at it later via the command option.

3. Add a config file at config/pug.php:

<?php
use Pug\Pug;

return [
    'basedir'            => resource_path('views'),
    'paths'              => [resource_path('views')],
    'extension'          => '.pug',
    'cache'              => env('APP_DEBUG') ? false : storage_path('framework/views/pug'),
    'cache_dir'          => storage_path('framework/views/pug'),
    'pretty'             => env('APP_DEBUG'),
    'strict'             => env('APP_DEBUG'),
    'expressionLanguage' => 'js', // 'php' if you want PHP expressions in templates
];

4. Write a tiny view engine. Pug\Pug renders directly, so extending Engine (not CompilerEngine) is the simplest correct integration:

<?php
namespace App\View;

use Illuminate\View\Engines\Engine;
use Pug\Pug;

class PugEngine extends Engine
{
    public function __construct(protected Pug $pug) {}

    public function get($path, array $data = [])
    {
        return $this->pug->render($path, $data);
    }
}

5. Register it. In AppServiceProvider::boot():

use App\View\PugEngine;
use Pug\Pug;

$this->app->singleton(Pug::class, fn () => new Pug(config('pug')));

$this->app['view.engine.resolver']->register('pug', function () {
    return new PugEngine($this->app->make(Pug::class));
});

$this->app['view']->addExtension('pug', 'pug');

6. First template. resources/views/welcome.pug:

doctype html
html
  head
    title= title
  body
    h1 Hello #{name}
    ul
      each item in items
        li= item

Route it: Route::view('/welcome', 'welcome', ['title' => 'Hi', 'name' => 'World', 'items' => ['a','b']]);

That's the whole loop. You can now use .pug files anywhere Laravel accepts a view name — view(), Mailable::view(), View::composer(), error pages, etc.

First meaningful use case: a marketing landing page or transactional email where Blade's verbosity gets in the way — Pug's indentation syntax pays off immediately on markup-heavy files.

Implementation Patterns

Layouts and partials. Use Pug's native extends/block/include — do not try to mix Blade directives:

//- resources/views/layouts/app.pug
doctype html
html
  head
    title= title
  body
    block content
//- resources/views/pages/about.pug
extends ../layouts/app

block content
  h1 About
  include ../partials/footer

Set basedir to resources/views so absolute-style include /partials/x resolves.

Mixins as reusable components — the closest thing to Blade components:

mixin button(label, href)
  a.btn(href=href)&attributes(attributes)= label
+button('Save', route).btn-primary

Passing Laravel-generated strings (route URLs, CSRF tokens, asset paths) as variables works fine under the default JS expression language.

PHP expression language, for helper-heavy views. Set 'expressionLanguage' => 'php' and write PHP directly inside Pug expressions:

p= e($user->name)
a(href=route('profile', ['id' => $user->id])) Profile

This is the switch that makes Pug feel native to Laravel — route(), asset(), csrf_token(), auth()->user() all become usable. Keep it consistent: don't mix JS and PHP expression languages across templates in one app, or your team will get confused about which = means what.

Shared data. View::share() and view composers work transparently because Laravel merges data before handing it to PugEngine::get(). Put all data shaping in the controller or composer, not in the template.

Cache warming on deploy. Cold renders shell out to Node (~50–200 ms per file). Warm renders hit the compiled PHP cache and are fast. Add an artisan command:

foreach (File::allFiles(resource_path('views')) as $file) {
    if ($file->getExtension() === 'pug') {
        $pug->render($file->getRealPath(), []); // just to compile
    }
}

Run it in your deploy pipeline after view:cache. Note that php artisan view:clear does not clear Pug's cache dir — delete storage/framework/views/pug explicitly.

Inline rendering for tests or dynamic mail bodies:

$html = app(Pug::class)->render('p= $name', ['name' => 'Ada']);

Non-existent paths are treated as template source, which makes unit-testing templates trivial.

Filters for custom transforms:

'filters' => [
    'markdown' => fn (string $text) => Str::markdown($text),
],
:markdown
  # Heading

Gotchas and Tips

  • Node in production is the #1 failure point. Shared hosts, some PaaS runtimes, and minimal php:fpm images have no node. Add a Node layer to your Dockerfile or pick phug/phug (the pure-PHP reimplementation) if you cannot guarantee Node. This is a hard architectural decision — make it early.
  • Pin the pug npm version. A pug@4 release can silently break generated PHP syntax with a pug-php/pug that expects pug@3. Lock it in package.json and in your image build.
  • strict defaults to false. Undefined variables render as empty strings — you will spend an afternoon hunting a "missing" value that was never passed. Enable strict in dev.
  • basedir is the include resolver. Relative include ../x works without it; absolute include /partials/x and extends need it set to resources/views. Get this wrong and errors are misleading ("file not found" pointing at the wrong path).
  • Cache staleness after git pulls. The render cache is keyed on file mtime. Deployments that preserve mtimes (rsync -a, some CI caches) can serve stale HTML. touch the .pug files or wipe the cache dir on every release.
  • pretty => true in production adds whitespace that can break pre, textarea, and inline elements. Keep it dev-only.
  • Ambiguous input to render(). A path that doesn't exist is compiled as source. If a view filename is typo'd, you get a confusing "unexpected token" compile error rather than "view not found" — validate paths in your engine if that bites.
  • Debug by reading the compiled PHP. $pug->compile($file) returns the generated PHP source — dump it whenever a template behaves unexpectedly. This is the single most useful debugging move.
  • command option for path discovery. When pug isn't on the shell PATH (common in containers), set 'command' => base_path('node_modules/.bin/pug'). npx pug also works but adds latency.
  • Don't put @csrf, @auth, @foreach in a .pug file. They are meaningless. Use Pug equivalents or precompute values in the controller.
  • Escape consciously. = and #{} escape; != and !{} do not. Under PHP expression language, calling e($x) inline is also valid but redundant.
  • Custom keywords and plugins (keywords, customKeywords, plugins options) are the extension point for domain-specific shorthand — but they compile at the Node layer, so they're more work than filters. Reach for filters and mixins first.
  • laravel-pug and similar packages are older integrations built around this engine or Phug. If you want batteries-included (publishable config, Blade-like directives, @pug inline), evaluate phug/laravel before rolling your own engine — but it swaps the engine implementation, so audit template compatibility.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource