Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

A Laravel 404 usually comes from one of four places: the incoming method or URI does not match a registered route, the route file is not being loaded, Laravel is using a stale route cache, or the web server is not forwarding the request to Laravel’s front controller. Start with php artisan route:list, compare the request exactly with that output, clear route cache when appropriate, and verify that the site root is Laravel’s public directory with unmatched requests sent to public/index.php.

The fastest way to choose the right fix is to identify which layer generated the response. A server-branded 404 points to Nginx or Apache; Laravel’s own error response means the request reached the application but no route matched.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Identify which layer produced the 404

Before changing route code, determine whether the request reached Laravel. This prevents spending time editing controllers when the web server never invoked PHP, or changing Nginx rules when Laravel deliberately rejected an unmatched URI.

What you observe Likely layer What to inspect first
A generic or company-branded Nginx/Apache 404 page, with no Laravel styling Web server or virtual-host routing Document root, rewrite rules, front-controller fallback, and server logs
Laravel’s exception or 404 page, or a response shaped like your application’s error handling Laravel application route:list, method, URI, route groups, constraints, and cache
The home page works but every deep link fails Usually web-server rewrite or document-root configuration Whether all non-file requests fall through to public/index.php
The same URL works with php artisan serve but fails behind Nginx or Apache Deployment configuration Virtual host, PHP-FPM target, release directory, and rewrite configuration

Check the response body and headers, then review the web-server access and error logs. A request that never appears in the PHP or Laravel logs is usually stopping before the framework.

Run the authoritative route check first

From the Laravel project directory, run:

php artisan route:list

This is the authoritative answer to “Did Laravel register my route?” The listing shows each route’s URI, allowed HTTP method, action, and middleware. If you need middleware details, use:

php artisan route:list -v

Find the route you expect and record its URI and verb exactly. If it is absent, the request cannot match it regardless of what is written in an editor. Fix registration or bootstrap loading before investigating the controller.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read the route output carefully

  • URI: This is the path Laravel matches after the host and scheme have been handled. A group prefix can make the registered URI different from the path in the route file.
  • Method: A route listed as GET will not satisfy a POST, PUT, PATCH, or DELETE request.
  • Action: Confirm that the listed controller class and method are the code you intended, rather than an older release or a different route with a similar URI.
  • Middleware: With -v, check whether middleware is redirecting, rejecting, or otherwise changing the request before the action runs. A middleware response is not the same diagnosis as an unmatched route.

Match the incoming HTTP method and URI exactly

Laravel matches both the HTTP method and the URI. For example:

Route::get('/reports', [ReportController::class, 'index']);

This route handles a GET /reports request. A form posting to /reports, a JavaScript client sending POST /reports, or a client calling a different prefix will not use it. Define the method the client actually sends, or change the client to send the method the route expects.

Inspect the request rather than guessing

  • For a browser navigation, copy the complete path from the address bar and check the browser’s network panel for the request method and final URL.
  • For a form, inspect the form’s action and method attributes. HTML forms natively submit GET or POST; Laravel method spoofing for other verbs must be configured correctly.
  • For fetch, Axios, mobile clients, or API tools, inspect the actual method, base URL, path, and redirects in the request details.
  • Compare query strings separately. A query such as ?page=2 does not change the route URI, but a missing or extra path segment does.

Check prefixes, slashes, and route groups

Group prefixes are part of the final URI. A route declared inside a group with a admin prefix is reached at /admin/..., not at the unprefixed path shown in the route file. Likewise, a route inside an API prefix or a versioned group may be registered under a path such as /api/v1/.... Use the URI printed by route:list instead of inferring it from a single declaration.

Compare the path character for character, including spelling, capitalization where the hosting filesystem or server makes it significant, and whether an extra segment is present. A trailing slash may be normalized or rejected differently by the web server and application, so test the exact URL shown in the route list and inspect redirects rather than assuming both forms are equivalent.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check domains and parameter constraints

Routes can be restricted to a host or domain, and parameters can have regular-expression constraints. A route that is correct for admin.example.test will not match the same path on another host. A constrained parameter also fails when the supplied value does not satisfy the constraint. Confirm the hostname, subdomain, scheme-related proxy settings, and parameter format when a route appears in the list but still returns 404.

Make sure Laravel is loading the route file

Browser routes normally live in routes/web.php; applications may also define API or other route files. Laravel’s directory structure places route definitions under the routes directory, while public/index.php is the entry point for incoming requests. If a route is missing from route:list, inspect how the application’s bootstrap configures routing.

Verify the file and syntax

  • Confirm the file was saved in the deployed release, not only in a local working copy.
  • Check that the route declaration is outside an accidentally disabled code path and that its imports resolve.
  • Ensure the application is loading the file you edited. Projects can customize route registration in their bootstrap configuration, so a route written in an unconfigured file will never be registered.
  • After syntax or autoload changes, run the route command again. A bootstrapping exception should be fixed as an application error; it is not evidence that the route itself matched.

If the route appears in route:list locally but not on the server, compare the deployed commit, environment, release directory, and bootstrap configuration. You may be inspecting one copy of the project while PHP-FPM serves another.

Clear stale route cache after route changes

Laravel can cache the compiled route collection for deployment. If cached routes are active, newly added or changed declarations are not used until the cache is removed or rebuilt. Clear the cache while diagnosing:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
php artisan route:clear

Run the command against the same application and release directory that serves the request. Then run php artisan route:list again and confirm the expected route is present with its current URI and method.

Rebuild intentionally in production

For a deployment that uses route caching, regenerate it after the new route files are in place:

php artisan route:cache

Laravel’s documented behavior is that newly added routes require a fresh route cache. Treat cache generation as a deployment step, not as a substitute for fixing an incorrectly registered route. If multiple release directories or servers are behind a load balancer, clear or rebuild the cache on every instance, then reload the relevant PHP process if your deployment process requires it.

Fix the web server’s document root and front controller

Laravel’s deployment guidance requires the web server to direct requests to the application’s public/index.php. The virtual host or site configuration should use the project’s public directory as its document root, never the project root. The project root contains application code and configuration that should not be exposed as public files.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Nginx: let non-file requests fall through to Laravel

An Nginx site needs a front-controller fallback so that a URI without a matching static file is sent to Laravel. The documented pattern is:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location ~ .php$ {
    fastcgi_pass unix:/path/to/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

Use the PHP-FPM socket or upstream appropriate for the server; the critical behavior is the try_files fallback to /index.php?$query_string and a PHP handler for that file. Set root to the Laravel public directory in the server block. After changing the site configuration, validate it with the server’s configuration test, reload Nginx, and confirm that the request reaches the intended PHP-FPM pool.

Apache: preserve the public rewrite configuration

Apache must serve the Laravel public directory and allow the rewrite rules shipped with that directory to operate. Ensure the required rewrite module is enabled, the virtual host points at public, and directory overrides are permitted where the configuration relies on the directory’s rewrite file. A server that serves existing files but does not rewrite unknown paths to public/index.php commonly produces the pattern “home page works, every deep link is 404.”

After changing Apache configuration, test the configuration and reload the service. Check both the access log and the Laravel log: if Apache logs a 404 without a corresponding application request, the problem remains at the server layer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the failure pattern to choose the next test

Only the home page works

When / loads but /reports or another deep link returns a server-branded 404, prioritize the document root and rewrite rules. The home page may be a real file or a route reached through a special default configuration, while other paths are never forwarded to the front controller. Confirm that Nginx has the try_files fallback or that Apache’s public rewrite configuration is active.

The route works with php artisan serve but not in production

The built-in server sends requests through Laravel’s front controller, so a production-only failure points to deployment context: the virtual host may target the project root, the wrong release, or a different PHP-FPM pool. Verify the hostname, document root, deployed code, PHP version and extensions expected by the application, and that the server configuration was reloaded after edits.

The route appears in route:list but still returns 404

First compare the incoming method, complete URI, host, and parameter values with the listing. Then check route constraints, group prefixes, and middleware behavior. If the response is a generic web-server page, stop investigating Laravel matching and repair front-controller forwarding. If the response is Laravel’s own 404, enable appropriate application logging for the request and inspect any binding or constraint that can intentionally turn a match into a not-found response.

The route is absent from route:list

Do not troubleshoot Nginx yet. Confirm the file is loaded, the declaration is syntactically valid, the deployed release contains the change, and no stale route cache is active. Run php artisan route:clear, then list routes again. If it remains absent, inspect the application’s bootstrap route configuration and the environment in which Artisan is running.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Fallback routes: useful for presentation, not repair

Laravel supports a fallback route for requests that match no other route:

Route::fallback(function () {
    return response()->view('errors.not-found', [], 404);
});

A fallback is appropriate when you want a controlled, branded response or a consistent JSON error for unmatched requests. It does not register a missing business route, correct a wrong HTTP method, clear route cache, or repair a web server that never forwards the request. Place it only after the intended routes and make its response explicit so that genuine mistakes are not hidden behind a misleading success status.

A complete, low-risk troubleshooting procedure

  1. Capture the failing request. Record the full URL, host, HTTP method, status code, response headers, and response body. Note whether the page is server-branded or clearly generated by Laravel.
  2. Check logs at both layers. Look at the web-server access/error logs and the Laravel application log for the same timestamp. This establishes whether PHP and Laravel received the request.
  3. List registered routes. Run php artisan route:list; use -v when middleware details matter. Search for the expected URI and verify its method and action.
  4. Compare the request literally. Correct the client, route, group prefix, domain, parameter, or method so they agree. Test the exact URI shown by the listing.
  5. Clear an outdated cache. Run php artisan route:clear, repeat the route listing, and only then rebuild with php artisan route:cache if the deployment intentionally uses caching.
  6. Confirm route loading. Check the deployed route file, imports, bootstrap configuration, and release directory. Ensure Artisan and PHP-FPM point to the same application.
  7. Verify the public root. Set the virtual host root to public, protect the project root, and ensure all dynamic paths fall through to public/index.php.
  8. Reload and retest. Validate and reload Nginx or Apache, confirm the PHP-FPM target, then retest with a fresh request that bypasses any browser cache.
  9. Add a fallback only for intentional UX. Use Route::fallback after the real cause is resolved, not as a diagnostic shortcut.

Preventing route 404s during deployment

  • Include route registration checks in deployment verification: run php artisan route:list against the new release and confirm critical URIs.
  • If route caching is part of the release process, rebuild it after publishing route files and before switching traffic.
  • Keep the web-server document root fixed at the release’s public directory and make the front-controller fallback part of versioned infrastructure configuration.
  • When using symlinked releases, verify that the PHP-FPM worker, CLI Artisan process, and web-server root resolve to the same release.
  • Test at least one static asset, the home page, and a representative deep link after every server or framework configuration change.
  • Preserve the distinction between a server 404 and a Laravel 404 in monitoring. They require different owners and different remediation paths.

What the official Laravel architecture implies

Laravel’s directory-structure documentation describes public/index.php as the entry point for all requests entering the application and the file that configures autoloading. Its routing documentation states that when no route matches, Laravel returns a 404 HTTP response. Deployment documentation therefore instructs the web server to direct requests to public/index.php. Together, these facts explain the diagnostic split: Laravel can only match a route after the server has handed the request to the front controller; a server-level 404 means that handoff did not occur.

Frequently Asked Questions

Why does changing the controller not fix my Laravel 404?

A controller runs only after Laravel has matched a route. Check the response layer and php artisan route:list first; if the route is absent, the method or URI differs, or the server never forwards the request to public/index.php, controller edits cannot affect the result.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should I add a fallback route to stop all 404 responses?

Only when you intentionally want a custom response for genuinely unmatched requests. A fallback does not fix a missing route, stale cache, incorrect HTTP method, or broken Nginx/Apache rewrite.

What should I do after adding a route in a cached production application?

Deploy the route to the serving release, run php artisan route:clear while diagnosing, verify it with route:list, and then run php artisan route:cache if route caching is part of that deployment.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.