Laravel CORS Issue when dealing with image files inside public folder?

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Laravel CORS Issue when dealing with image files inside the public folder

Dealing with Cross-Origin Resource Sharing (CORS) errors is one of the most frustrating hurdles in modern web development, especially when integrating a Single Page Application (SPA) like Vue.js with a backend framework like Laravel. When you move from serving content directly via your domain (project.test) to fetching assets from localhost:8080, the browser's security policies become much stricter.

This post dives deep into why accessing static files within the public folder can trigger these CORS errors, and how a senior developer should approach solving this problem in a Laravel environment.

Understanding the Root Cause of the CORS Problem

The error message you are seeing—Access to fetch at '...' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present—tells us exactly what the browser is complaining about.

When your Vue application running on http://localhost:8080 tries to fetch an image from your Laravel server, the browser performs a security check. If the response headers from the server do not explicitly grant permission for the requesting origin (localhost:8080), the request is blocked, regardless of whether the file exists on the server itself.

The confusion arises because when you access project.test/images/file.jpeg directly in your browser (from a different context), it works fine. This is often because the direct access bypasses the complex cross-origin security checks that occur during an AJAX or fetch request initiated by another domain.

Why laravel-cors and .htaccess Might Fail for Static Files

You correctly noted that applying standard CORS middleware (like laravel-cors) might not directly solve this when dealing with static assets in the public directory, as it is primarily designed to manage API responses. Similarly, manipulating the .htaccess file while using Valet adds another layer of complexity because you are trying to inject specific header logic based on the request origin within a server configuration file that manages Laravel routing.

The fundamental issue here is not what the server serves, but how the server configures the response headers for static files requested via HTTP methods like GET.

The Recommended Solution: Serving Assets via Laravel Routes

Instead of relying on raw public file access to solve cross-origin issues, the most robust and Laravel-idiomatic solution is to intercept the request in your Laravel application. This ensures that all data delivery—whether it's an API response or a static asset—passes through controlled middleware where CORS policies are explicitly managed.

Here is a step-by-step approach:

Step 1: Restructure Asset Delivery

Instead of making the image directly accessible at http://project.test/images/filename, you should create a route in your Laravel application to serve these files. This gives you full control over the response headers.

In routes/web.php:

php
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;

Route::get('/images/{filename}', function ($filename) {
    // Ensure the file exists in your public/images directory
    $path = 'images/' . $filename;
    if (!Storage::disk('public')->exists($path)) {
        abort(404);
    }

    $fileContents = Storage::disk('public')->get($path);
    $mimeType = Storage::disk('public')->mimeType($path);

    // Return the file content with correct headers
    return response($fileContents, 200, [
        'Content-Type' => $mimeType,
        'Access-Control-Allow-Origin' => '*', // Or specify your exact frontend domain
        'Access-Control-Allow-Methods' => 'GET',
    ]);

})->where('filename', '[a-zA-Z0-9_-]+'); // Basic sanitization for security

Step 2: Configure CORS Globally (The Laravel Way)

Once you are handling the delivery through a controlled route, you can configure your CORS settings globally using packages or custom middleware. This is cleaner than file-level hacks. For comprehensive API and asset CORS management, exploring solutions that integrate well with the framework structure—like those discussed on the official https://laravelcompany.com documentation regarding API design—will be beneficial.

If you are setting up your application for external consumption, make sure your config/cors.php file is correctly configured to allow requests from your Vue development origin (http://localhost:8080).

Conclusion

Trying to patch CORS issues by modifying .htaccess files for static assets often leads to brittle solutions that break when moving between local development (Valet) and production environments. The correct approach in a Laravel application is to treat all data delivery, including static assets, as controlled endpoints. By serving images through a defined route within your Laravel application, you gain the necessary control to inject precise CORS headers, ensuring a secure, predictable, and maintainable experience for your Vue frontend.