Facades in Laravel: Do You Need To Use Them? [OPINION]

Have you ever used Auth::user() in Laravel? So yeah, that Auth is a Facade. Question: do you actually need to know how they work, and would you need to create your own facades?

Disclaimer: this article is written by Modestas, more like an opinion. Facades are one of those topics that have different opinions around them, so I'm open to discussions here or on Twitter.


What are Facades?

First, the definition.

Reading Laravel documentation about Facades you might get a little confused about what they are. The documentation says:

Facades provide a "static" interface to classes that are available in the application's service container.

Along with that, they also say:

Laravel Facades serve as "static proxies" to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.

Wait, what does that actually mean?

Well, you won't have to know what class is underneath the Facade. You can just call the Auth facade and access methods from the underlying class.

Facades in Action

In Laravel, we can call Auth::user() to retrieve the user from the session.

What we don't see under the hood, it is a static proxy to the Illuminate\Auth\AuthManager class. The AuthManager class has a method called user() that returns the user from the session.

Facade makes our experience as developers easier as we have to only remember the Auth Facade, and we get instant static access to the user() method.

Let's quickly compare facade usage with the usage of the class itself to illustrate the difference.

How would it look without Facades?

Creating New Class Instance

use Illuminate\Auth\AuthManager;
 
public function index()
{
$auth = new AuthManager();
$user = $auth->user();
}

Or, a bit shorter, with Dependency Injection.

Using Dependency Injection

use Illuminate\Auth\AuthManager;
 
public function index(AuthManager $auth)
{
$user = $auth->user();
}

With Facade under the hood, it's just one line.

Using Facade

public function index()
{
$user = Auth::user();
}

So, in short, Facades are just like a shortcut to a specific class.

Now, when we know what they are, let's think if we need to use them, and how.


USING Facades is Great

Let's start with what I see as good at using Facades.

Use Facades from Framework Core

It's convenient to use the Facades from Laravel core. It just works, and you don't have to remember any of the long class names.

Great for those that are learning to get things running. Great for those that are developing systems rapidly.

Imagine if you'd had to remember all of these:

It's much better to quickly remember their Facades and use them:


Use Facades from Packages

Package creators can also benefit from Facades due to the same reason as we have in the framework itself - it's easier to remember the name of the Facade than the name of the class. Let's look at a few package examples:

Spatie Activity Logs

https://spatie.be/docs/laravel-activitylog/v4/advanced-usage/batch-logs

In this package, we can find a Facade called LogBatch which is a shortcut for the Spatie\Activitylog\LogBatch class.

Laravel Debugbar

https://github.com/barryvdh/laravel-debugbar

This package also contains a Facade that's called Debugbar which is a shortcut for the Barryvdh\Debugbar\LaravelDebugbar class.

It just gives the end user a better interaction to use some functionality at any point statically.


CREATING Your Own Facades: Not So Great

Oh cool, so you would think you can create your own "shortcut" Facades and use them anywhere in your Laravel application?

And here's the part where I think Facades are not that good. Used in the wrong way, they may cause problems with tooling or overall experience.

Issues With Auto-Completion

When you use Facades, you don't have access to the methods that are available in the class. This can cause some issues with auto-completion in your IDE.

For example, imagine that you have a Service class called SearchService that has a method called get():

app/Services/SearchService.php

namespace App\Services\SearchService;
 
class SearchService
{
public function get(string $query): array
{
// ...
}
}

To create a "shortcut" to it, you create a Facade called Search:

app/Facades/Search.php

namespace App\Services\Facades;
 
use Illuminate\Support\Facades\Facade;
 
class Search extends Facade
{
protected static function getFacadeAccessor()
{
return \App\Services\SearchService::class;
}
}

So now you can use Search::get(), right?

Cool, but your IDE might not show that the class exists or that it doesn't have any methods!

And that's true, because your Facade class doesn't have the get() method in it.

You can make the IDE autocomplete work, by adding doc blocks to the Facade class:

app/Facades/Search.php

namespace App\Services\Facades;
 
/**
* @method static get(string $query)
*/
class Search extends Facade {
// ...
}

But you'll also have to manage another file to make sure that all methods are added to the Facade. Seems complicated.


Facades Can Override The Names of Classes

When you create a Facade, you don't have to follow the same Class name that you intend to call. This means that I can use whatever name I want for the Facade, and it will still work. Let's look at an example:

Creating a Facade

class MyRandomClassName extends Facade
{
protected static function getFacadeAccessor()
{
return \App\Services\SearchService::class;
}
}

config/app.php

// ...
'aliases' => Facade::defaultAliases()->merge([
// ...
'MyRandomClassName' => \App\Services\Facades\MyRandomClassName::class,
])->toArray(),

Facade Usage

\MyRandomClassName::get('query');

And now I can use the MyRandomClassName facade to call the Search class. No imports are needed as you can access it globally.

Even worse is the fact that this class might not even exist! How? Well, we are creating an alias. Let's change the config a bit:

config/app.php

// ...
'aliases' => Facade::defaultAliases()->merge([
// ...
'MadeUpAlias' => \App\Services\Facades\MyRandomClassName::class,
])->toArray(),

Facade Usage

\MadeUpAlias::get('query');

And this will still work! But if you will try to search globally for MadeUpAlias, there won't be any results. This is because it's not a real class. It's just an alias for a class that exists.

Notice: I know this example is exaggerated. But it gives you a great example of how you can use Facades in the wrong way to add more confusion to your codebase.


Facades Can be Used Anywhere

One thing that Facades have for them is being able to use them anywhere you want. Great thing, right?

Do you need it in a View, Controller, Service, or anywhere else? No problem - it's there.

But it's a quick way to break the MVC pattern, and run complex logic where you are not supposed to.

Imagine you have created a Facade for a Service that is generating a big report table. Use it in a Controller and it will be good. But use it in View, and we have a problem.


Facade Tutorials Don't Show Real-World Usage

When you look at tutorials on how to create Facades, they are usually very simple. They are just a shortcut to a class that returns something simple.

But in real-world scenarios, Facades are meant to be used as a Proxy Class to gain static access to methods that are not static like in the Auth Facade.

When it stops being cool is where you can quickly get out of hand and move everything into facades which would quickly lead you to scope creep and one class might start doing the work of 10 others.


Conclusion

I'd say that Facades are convenient and easy to use, from framework and packages. But if we try creating your Facades - that story changes. You have to really know what you are doing, then.

It would be better to think about how you can structure the project with different design pattern(s), to avoid having a global class (Facade) that's callable anywhere.

What do you think? Let's discuss in the comments!

avatar

I think helpers can be converted to facades.

avatar

Could you expand on that idea? I'm not sure about the case you mentioned so would love to hear more

avatar

I'm still a novice and starting to dig deeper on all the features Laravel has to offer. I found the facades very user friendly and a good way to get things moving like you mentioned in the article. Some examples of when not to use them in the views would be great. Thanks for the article! -Mike Swan

avatar

Facades are indeed very user friendly but as mentioned in the article - mainly for packages/framework itself. So those being used in a view - might not cause problems. It's just like any globally available function.

An example of when it shouldn't be used in views specifically is for DB facade. This is because it makes a query to the database and that's not the correct place for it to stay. You might think that it's rare but sometimes you just don't think about it or completely understand and it gets in your code.

Other examples might include your custom Facades that does something to retrieve the data. View should only receive data from controller (to clarify, I'm mainly talking about DB data, files data) and not from a Facade that has a Service class under it.

Hope that helps you a little bit, if not - feel free to comment back and I can expand either the article or the comments!

avatar

such a greart article really learned a lot. i've question though i've added user model to the class aliases to get access to const variable globally from user model, was doing this a bad choice?

avatar

If it's a global parameter, I would probably add it to the config() instead of the User model.

avatar

actually my scenario is in my user model i've const variable like

const TYPE_CUSTOMER
const TYPE_ANALYST

in some of my blade i need to check something like Auth::user() == App\Models\User::TYPE_* i don't want to use full namapse for referencing User so i added the User => App\Models\User to the aliases array. so, i'm bit confused about putting it there, and would really appriciate your thoughts on it.

avatar

I would personally be fine with using full namespace, the alias may confuse someone where that shorter User comes from, personally I wouldn't think to look at the Aliases, as I personally have never used it this way in my 10 years with Laravel.

So if you're doing something non-standard like this, it may work for you but may confuse other developers in the future.

avatar

thank you for the explaination, from now i will be using full namespaces.

avatar

i would love to see this example with interface implementation and updating the doc blocks with interface example

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 58 courses (1054 lessons, total 46 h 42 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials