Skip to main content
Facades

Facades

A facade provides a static-looking interface to a class resolved from the service container. Cache::get(), DB::table(), and Route::get() are facades. Behind the scenes, the call is forwarded to a real object, which keeps testability and dependency injection intact.

How a facade works

Each facade defines getFacadeAccessor(), which returns a container key. When you call a static method, the base facade resolves that key and forwards the call.

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class Sms extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return 'sms';
    }
}

Registering the binding

use App\Services\SmsGateway;

public function register(): void
{
    $this->app->singleton('sms', function ($app) {
        return new SmsGateway($app['config']['services.sms']);
    });
}
use App\Facades\Sms;

Sms::send($number, 'Your code is 4821');

Real-time facades

Any class can be used like a facade by prefixing its namespace with Facades\. This is convenient in quick scripts and tests, but explicit injection is usually clearer in application code.

use Facades\App\Services\InvoiceCalculator;

$total = InvoiceCalculator::total($items);

Facades versus injection

Constructor injection makes dependencies visible and easy to replace in tests. Facades shorten code and are convenient in views and legacy sections. A balanced approach is to inject services into controllers and use facades for framework utilities such as Cache, Log, and DB.

// injected dependency
public function __construct(private InvoiceCalculator $calculator)
{
}

// framework utility
$value = Cache::remember('stats', 600, fn () => $this->calculator->stats());

Testing with facades

Laravel's facades include fake helpers for framework services. For custom facades, swap the binding in the container or mock the underlying class.

Cache::shouldReceive('get')
    ->once()
    ->with('stats')
    ->andReturn(['users' => 10]);

Mail::fake();
Queue::fake();
Bus::fake();

Common pitfalls

  • Forgetting to register the container binding behind a custom facade.
  • Using real-time facades in hot paths where a normal dependency would be clearer.
  • Assuming facades are globally available in every namespace; import them explicitly.
  • Mocking a facade when a fake is available; fakes preserve more framework behavior.