DEV Community

marius-ciclistu
marius-ciclistu

Posted on • Originally published at marius-ciclistu.Medium on

The Zero-Cost Boot Hack Every Maravel Developer Needs to Know


Maravel Micro-Framework

I had to configure the mail on Maravel.

The Lumen usual path would had been:

// bootstrap/app.php
$app->configure('mail');

$app->alias('mail.manager', Illuminate\Mail\MailManager::class);
$app->alias('mail.manager', Illuminate\Contracts\Mail\Factory::class);

$app->alias('mailer', Illuminate\Mail\Mailer::class);
$app->alias('mailer', Illuminate\Contracts\Mail\Mailer::class);
$app->alias('mailer', Illuminate\Contracts\Mail\MailQueue::class);

$app->register(Illuminate\Mail\MailServiceProvider::class);
Enter fullscreen mode Exit fullscreen mode

But this will execute those on each request even if the request will not send any email.

This is where Lumen’s architecture shines because it considers all of its internal service providers as deferred, without them needing to implement \Illuminate\Contracts\Support\DeferrableProvider interface.

The make method from Lumen Application looks in $availableBindings and registers the needed provider/s before resolving from container:

public function make($abstract, array $parameters = [])
{
    $abstract = $this->getAlias($abstract);

    if (
        !$this->bound($abstract) &&
        array_key_exists($abstract, $this->availableBindings) &&
        !array_key_exists($this->availableBindings[$abstract], $this->ranServiceBinders)
    ) {
        $this->{$method = $this->availableBindings[$abstract]}();

        $this->ranServiceBinders[$method] = true;
    }

    return parent::make($abstract, $parameters);
}
Enter fullscreen mode Exit fullscreen mode

In Maravel, the Lumen Application is extended by \App\Application. To add your bindings without paying a runtime performance penalty, you should redefine the static arrays. (Note: We deliberately copy the core bindings from the parent class rather than using array_merge() in the constructor. In a micro-framework, static property definition is cached by OPcache and costs zero CPU cycles, whereas merging arrays at runtime slows down every single request.)


use Illuminate\Mail\MailServiceProvider;

public $availableBindings = [
    // copy from parent
    'mailer' => 'registerMailBindings',
    'mail.manager' => 'registerMailBindings',
];

protected function registerContainerAliases(): void
{
    $this->aliases = [
      // copy from parent
      \Illuminate\Mail\MailManager::class => 'mail.manager',
      \Illuminate\Contracts\Mail\Factory::class => 'mail.manager',
      \Illuminate\Mail\Mailer::class => 'mailer',
      \Illuminate\Contracts\Mail\Mailer::class => 'mailer',
      \Illuminate\Contracts\Mail\MailQueue::class => 'mailer',
    ];
}

protected function registerMailBindings(): void
{
    $this->singleton('mail.manager', static function (self $app) {
        return $app->loadComponent('mail', MailServiceProvider::class, 'mail.manager');
    });

    $this->bind('mailer', static function (self $app) {
        return $app->loadComponent('mail', MailServiceProvider::class, 'mailer');
    });
}
Enter fullscreen mode Exit fullscreen mode

In this way your mail provider will not be booted on each request keeping the boot time small.

This comes built-in (commented out) in Maravel 10.52.42, so if you need it you just have to uncomment a few lines of code from \App\Application and composer.json exclude-from-classmap:

 "vendor/macropay-solutions/maravel-framework/illuminate/Mail/",
Enter fullscreen mode Exit fullscreen mode

Then, regenerate your autoloader:

composer dump-autoload -o
Enter fullscreen mode Exit fullscreen mode

The Bottom Line: If your application only needs a functionality sometimes, you should never register its provider globally. By using Maravel’s built-in deferred bindings, your mail provider will sleep quietly until the exact moment an email is actually sent, keeping your boot times blazing fast.

NOTE

Maravel auto-caches the configs on post-autoload-dump composer event so you have to configure all files in bootstrap/app.php. If you forget, the mail config will NOT be loaded when needed.

if (!$app->configurationIsCached()) {
    $app->configure('app');
    $app->configure('laravel_crud_wizard');
    $app->configure('mail');
}
Enter fullscreen mode Exit fullscreen mode

Update 2026.03.14
Version 10.52.43 of Maravel that requires Maravel Framework 10.66.3 contains a faster version of how to register a deferred provider:

protected function registerMailBindings(): void
{
    $this->configure('mail');
    $this->register(MailServiceProvider::class);
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)