The Laravel 8 framework brings a series of new features, improvements in known functions and some structural changes. One of these changes was the removal of the standard “Namespacing”, so it has generated some confusion and the “Target Class [Controller] not exist” error.

This change is compatible with previous versions, which means that older projects that used Laravel 7.x can easily migrate to Laravel 8.X, without changing anything because the basic structure of [its components](/componentsFramework-Laravel Architecture/) is maintained, but new projects created in Laravel 8 should take this into consideration.

The problem arising from this change in its newly created Laravel 8 applications when trying to carry the routes faces an exception such as:

Target class [MeuController] does not exist.

The problem is not necessarily related to a code error, but to a necessary adjustment, especially taking into account that 99.9% of the tutorials about Laravel (at least until version 7) did not depend on this standard Namespace adjustment to routes configuration.

Fixing the error “Target class XXX does not exist”#

Until the Laravel Framework version 7, the RouteServiceProvider.php file had the following code in the$namespace property configuration:

<?php

    protected $namespace = 'App\Http\Controllers';

...

    public function boot()
    {
        ...
        Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web.php'));

In reading this code: By default Laravel set up service to load the routes on routes/web.php, using middleware web and namespace App\Http\Controllers. This, in turn, means that whenever you declare a route using the string syntax, the laravel will look for the controlling class, considering as “root” the App\Http\Controllers folder. As in the example of setting up a route:

Route::get('posts', '[email protected]');

What change occurred in Laravel 8? Simple but impactful, the $namespace variable is no longer configured by default on RouteServiceProvider, and the route loading declaration/configuration has changed to:

Route::middleware('web')
    ->group(base_path('routes/web.php'));

This means that the Laravel is looking for routes within your web.php file, as always_. It is also applying the web middleware, as always_. However, note that it is no longer using the previous namespace.

This means that from Laravel 8, when you declare your routes using the string syntax, the Laravel framework will not look for your controller within App\Http\Controllers. And if you use this syntax, the exception error Target Class [Controller] does not exist will be released.

How to fix “Target class XXX does not exist”?#

First let’s understand the problem generated: Laravel does not know where to look for your controller, so you need to “inform” it where the class is.

There are 3 ways to do this:

  1. Adding $namespace again in the configuration so that you can continue using the routes as you did in Laravel 7.x and previous versions
  2. Use the full Namepace in your route files when using the string syntax
  3. Use the action syntax (recommended)

Adding the configuration of the $namespace#

This is quite simple. Open the RoutesServiceProvider.php file, first enter the following line at the beginning of the class (or remove the comment if it exists like this):

protected $namespace = 'App\Http\Controllers';

Then add the call to the namespace method for each route setting in the boot function. The result must look like the following code:

public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        Route::prefix('api')
            ->middleware('api')
            ->namespace($this->namespace) // <- This line must be inserted
            ->group(base_path('routes/api.php'));

        Route::middleware('web')
            ->namespace($this->namespace)  // <- This line must be inserted
            ->group(base_path('routes/web.php'));

        ...
    }

In this way we set up the laravel routes again so that it considers App\Http|Controllers the base for its discovery.

Using the complete namespace#

This change involves changing all your route statements. Although laborious is simple: prefix the names of your controllers with their namespaces. In the following example for a PostsController class within the app/Http/Controllers folder:

// Note how we add the full namespace before the class name
Route::get('posts', 'App\Http\Controllers\[email protected]');

Using the action syntax#

This is the most recently recommended alternative because it is less susceptible to typing errors and, in my experience, offers better IDE support, as we explicitly inform the code which class to use.

Therefore, instead of using usual string syntax, we can use the action syntax where we specify the class and the method to be used in a matrix as a route parameter being configured:

// String syntax
Route::get('posts', 'App\Http\Controllers\[email protected]');

// Syntax Action. 
use App\Http\Controllers\PostsController;

Route::get('posts', [PostsController::class, 'getAll']);

Note that to use the action syntax you need to import the class in the route file, using use App\Http\Controllers\ArtigosController, this will be required for all controller classes to be used.

The attribute of the PHP, ::class classes will bring the full namespace, along with the class name, so the Laravel will know where to find the controller and will perform the method passed in the second of the array position, in our example the getAll method.

Final considerations#

Now your application must work properly. If you still find problems, feel free to ask for help.You can find me on Twitter as @nunomazer .

If you added Namespace manually, you specified it complete on your routes, or followed with the action syntax, what you just did was tell Laravel how to find your controllers in the application structure.