Because they are in a web folder.
If you have private user images don't expose them to the web.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
<?php
class RegisteredUserController extends Controller
{
public function store(Request $request): RedirectResponse
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'lowercase', 'email:strict,dns', 'max:255', 'unique:' . User::class],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
'profile' => ['required', 'image', 'mimes:jpeg,png', 'max:2048'],
], [
'profile.max' => 'The profile image must not be larger than 2MB.',
]);
if ($request->hasFile('profile')) {
$profilePath = $request->file('profile')->store('profiles', 'public');
}
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'profile' => $profilePath,
]);
event(new Registered($user));
Auth::login($user);
return redirect(route('dashboard', absolute: false));
}
}
example profile value in user: profiles/CKyXwwZFVGJ5ghhkfUBQfXDsMgw4eliC2iz8YFLN.jpg
why i can do thses 3 without even php artisan storage:link and they still works, i can still see the image?:
<img src="{{ auth()->user()->profile }}" />
<img src="{{ asset(auth()->user()->profile) }}" />
<img src="{{ asset('storage/' . auth()->user()->profile) }}" />
the image is stored in the `storage/app/public/profiles/filename.jpg' (note that i haven't symlink it yet and i haven't configure the filesystems.php)
I created another project and tested this again, the same setup, laravel new imagebugtest no starter kit, then i composer require laravel/breeze --dev then php artisan breeze:install
Then in dashboard.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Dashboard') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<img src={{ auth()->user()->profile }} />
<img src={{ asset(auth()->user()->profile) }} />
<img src={{ asset('storage/' . auth()->user()->profile) }} />
<div class="p-6 text-gray-900">
{{ __("You're logged in!") }}
</div>
</div>
</div>
</div>
</x-app-layout>
corresponds to the following src when inspected:
<img src="profiles/dmciGSr4LOEXVcyr5iIpyU3b14eWEEFzuvYHCIzz.png">
<img src="http://imagebugtest.test/profiles/dmciGSr4LOEXVcyr5iIpyU3b14eWEEFzuvYHCIzz.png">
<img src="http://imagebugtest.test/storage/profiles/dmciGSr4LOEXVcyr5iIpyU3b14eWEEFzuvYHCIzz.png">
Since I am just using npm run dev or npm run build to view the website, since composer run dev is clunky in Herd (the port is not displaying when it tries to run the php artisan serve part of that command)
I tried first php -S localhost -t public and I can see that the three images doesn't work (which is intended) then after i php artisan storage:link the 3rd img tag with
<img src={{ asset('storage/' . auth()->user()->profile) }} />
only displays the image!
I also tried to use the `php -d variables_order=GPCS artisan serve (not sure why i need to include the -d variables_order=GPCS, i found that this is a problem in herd, and why this is not the default if this is the working solution lol)
the result of this is similar when i serve the project with PHP's built-in server.
I think the problem is with the Herd itself (unlikely) or the way i installed Herd or PHP.
Please or to participate in this conversation.