Enabling Middleware Based on Environment in Laravel

Last updated 29th October, 2023

Introduction

By enabling middleware based on environment, developers can ensure that their application behaves differently depending on the environment it is running in. For example, developers can use this feature to enable debugging middleware in the development environment and disable it in the production environment. Alternatively maybe you have some error tracking software like Sentry, or custom logging to GCP that you only want running in production environments.

Usng the 'App::environment' method that Laravel provides, we can check the environment that your application is in.

Setting Up Some Example Middleware

To demonstrate how to enable middleware based on environment in Laravel, let's set up some example middleware.

First, create a new middleware using the following command:

php artisan make:middleware ExampleMiddleware

This will create a new file called ExampleMiddleware.php in the app/Http/Middleware directory.

Next, open the ExampleMiddleware.php file and add the following code:

namespace App\Http\Middleware;

use Closure;

class ExampleMiddleware
{
    public function handle($request, Closure $next)
    {
        Log::debug('ExampleMiddleware: Triggered');

        return $next($request);
    }
}

This is a basic middleware example that simply passes the request through to the next middleware in the pipeline. You can add your own custom logic to this middleware as needed. In our case, we'll add a simple log so we can see when it gets triggered.

Finally, register the middleware in the app/Http/Kernel.php file. Add the following code to the $routeMiddleware array:

'example' => \App\Http\Middleware\ExampleMiddleware::class,

Now you can use the example middleware in your routes or controller methods as needed.

Enabling Middleware Based on Environment

Basic Conditional Statements

Now, let's modify the ExampleMiddleware class to only run in the production environment. To do this, add the following code to the handle method:

if (! app()->environment('production')) {
    return;
}

This will ensure that the middleware only runs in the production environment.

This is arguably the simplest method of ensuring the logic in your middleware only runs in a specific environment. But there are a couple of other strategies.

Conditional Registration of Middleware

If you prefer, you can add conditional arguments directly to the middleware stack in App\Http\Kernel.php. This is probably the next simplest solution, and has the added benefit of keeping all of your environment configuration details in the Kernel.

protected $middleware = [
    // ... Other middleware	

    app()->environment('production')
        ? \App\Http\Middleware\ExampleMiddleware::class
        : ''
];

In the above example we very simply append on the class in the correct environment. But what if we want to append more than one set of middleware to the stack? We can do that too:

protected $middleware = [
    // ... Other middleware	

    ...app()->environment('production') ? [
        \App\Http\Middleware\ExampleMiddleware::class,
        \App\Http\Middleware\ExampleMiddlewareTwo::class,
    ] : []
];

The above example merges the $middleware array and the example classes when the environment is set to production.

Creating Environment Groups

Another neat solution is to create a middleware property in the App\Http\Kernel class and add your example middleware to that group. Then, add a conditional statement to check if the application is running in the production environment using the App::environment() method.

If the application is running in the production environment, the middleware group can be added to the global middleware stack.

// App\Http\Kernel.php

public function __construct(Application $app, Router $router)
{
    parent::__construct($app, $router);

    if (app()->environment('production')) {
        $this->middleware = array_merge(
		        $this->middleware,
		        $this->productionMiddleware
        );
    }
}

protected $productionMiddleware = [
    \App\Http\Middleware\ForceHttps::class,
];

In the above example, the ExampleMiddleware is only added to a new production middleware property. Then, in the constructor of the App\Http\Kernel class, a conditional statement is used to add the production middleware global middleware stack, if the application is running in the production environment.

You could extend this for other environments too, if you had a stack of middleware for each:

public function __construct(Application $app, Router $router)
{
    parent::__construct($app, $router);

    $this->middleware = array_merge(
		    $this->middleware,
		    $this->{app()->environment().'Middleware'}
    );
}

protected $productionMiddleware = [
    \App\Http\Middleware\ProductionMiddleware::class,
];

protected $testingMiddleware = [
    \App\Http\Middleware\TestingMiddleware::class,
];

protected $developmentMiddleware = [
    //
];

Laravel will automatically detect the environment you're in, and add that middleware stack to the global stack of middleware in your application.

Conclusion

As you can see, there are a bunch of different ways you can handle this kind of logic in a Laravel app. These are just a few that I've personally employed in my experience. What you choose to use will come down to what you find easiest to work with, and what suits the complexity of you app best.

Simple apps might just need a few conditions here or there. More complex apps might warrant adding some of the more dynamic strategies in.

Hope this helps 🤙

No comments yet…

DevInTheWild.

Login To Add Comments.

Want More Like This?

Subscribe to occasional updates.

Related Articles