When working with files and images in Laravel, you can store them for public and private use. In this tutorial, we will explore how to do both, also looking at local server and Amazon S3 setup.
1. Local Server: Storing Public Files
1.1. /public Directory
The public/ directory is the default location where Laravel serves static assets like images. By default, any file in the public directory can be accessed by users using a URL that points to the file.

If we put the cat.jpg image under the public/images/ folder, it can be accessed via the /images/cat.jpg URL.
Note: your web server's document root should be set to the
public/folder of your Laravel project. All files in this directory will be publicly accessible.
It is important to address that if you add any files to the public/ directory during some method calls, and have already configured the repository, your repository will become dirty. So this is suitable only for static files which you do not intend to manage on a software level.
1.2. /storage/app/public Directory
Now let's put the cat.jpg file in the storage/app/public directory and try to access it.

The storage/app/public/ directory in Laravel is a directory where you can store files that are publicly accessible to users. This directory provides a convenient location to store user-uploaded files, such as images, videos, and documents.
When files are stored in the storage/app/public/ directory, they are not directly accessible by users via URL. Instead, Laravel provides a symbolic link to the files in the public/ directory, making them accessible to users through a URL.
To create a symbolic link to the storage/app/public directory, you can use the php artisan storage:link command. This will create a symbolic link from the public/storage path to the storage/app/public/ directory.
Once the symbolic link has been created...
Premium Members Only
This advanced tutorial is available exclusively to Laravel Daily Premium members.
Already a member? Login here
Premium membership includes:
Comments & Discussion
My standard note for anybody coming here: Web devs should strongly consider leveraging image servers such as cloudinary or cloudflare (several others) when storing & serving image files!
- all the variant/conversion work handled, so you can efficiently pull appropriately sized & formatted images into the site without you having to juggle files.
- all the mime-type conversions to browser-friendly data types (e.g. WebP / AVIF, etc.) on a per-client basis handled without you having to juggle files.
- srcset / responsive images handled without you having to juggle files.
- images served from "cloud" (like S3 above).
- secure direct uploads, so using something like FilePond client your server never acts as intermediary during upload (as in example above).
- many other cool features (vary by service): ** Ability to serve private images (copied URL will not work outside your site even though not served from your site) ** streaming capability ** analytics ** global CDN network ** etc.
There is a learning curve and expense. Even though it is pretty basic and documentation is sparse, I've settled on cloudflare w/ monthly fee of $5 for first 100K images stored (no fee for variants/conversions of your uploaded image) + $1 per 100K images served. Cheap for the money!
all the variant/conversion work handled, ....... srcset / responsive images handled without you having to juggle files.
This is easy handled by eg. spatie/laravel-medialibrary
images served from "cloud" (like S3 above).
So you pay through the nose... Doesn't looks like an advantage to me.
secure direct uploads, so using something like FilePond client your server never acts as intermediary during upload (as in example above).
I have it easily done by myself. No need of cloud abra cadabra
many other cool features (vary by service): Ability to serve private images (copied URL will not work outside your site even though not served from your site) streaming capability analytics global CDN network etc.
Private images is no problem whatsoever. CDN yes it this case I agree.
There is a learning curve and expense. ...Cheap for the money!
The cloud stuff needs extra learning so it's not true. And the Laravel/Spatie docs are quite OK so not true either. My server costs me nothing more as I already have it so not ture as well. Also this 5 bucsks quickly become 50 when you want fast and reliable storage not the most basic one which is usually quite useless.
So I'm not buying it. I don't mean that the cloud is worthless. It surely is useful for many cases. But it is not a good solution for everything and everyone. And I definitely do not agree with your statement that every web dev should strongly consider leveraging image servers such as cloudinary or cloudflare. It all depends on the case and usually it is not the case for people who are in small projects where you have 100ish photos stored.
Well it's not to have a big debate and it sounds like you have this all in hand ... just a note that the option should be considered. And yes the size of the project does matter.
Just FYI one example of a "small" site I have: about 2K user-uploaded images that are served about 250K times per month in many variants. The UI/UX person can do whatever they want without having me spin up new variants, etc. About $8/month. It just works & I hardly think about it! (I view cloudflare about as reliable AWS, which means very much so ... probably more so than my own site!) I have used media library / S3, etc., in the past and they really are very good options, but no comparison at all for me and I will never go back.
But that's just info for folks every dev & every project different! You do have some cool stuff going on that would add to this guide: How do you actually do the direct to server (e.g. S3) uploads securely? And how do you serve tokenized (URL's expire) images from remote storage without hitting your server?
For people doing this tutorial now, the layout of amazon AWS has changed, but most things you will find. This step: 10. Select Application running outside AWS option and press Next
You should select "Other" and then it all works as you would expect. I have to say I tried first by getting a digital ocean Spaces to work but I can't figure that out yet.
I'd love to have a part of this tutorial that teach us how to store the photos on a static server. Eg. I could have an Ubuntu server with just ssh and nginx and serve the files like this: https://static.example.com/images/001/cat.jpg
Personally I've never used it this way, I've always saved files either on the same server or on Amazon S3. Why bother creating (and maintaining!) a separate server just for photos?
I'd say the reason is the same as why bother to use S3. In my case to have super fast, sessionless and cheap storage for millions of photos. Maintaining such server is so easy - much easier than S3. And cheaper.
Using something like https://github.com/minio/minio might work. Haven't tried. It is also mentioned in the Laravel docs
This MiniIO looks VERY interesting. Thank you Nerijus!