Storing a photo in Laravel. Migration file's structure
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# Storing Photos in Laravel: Mastering Migration Structure for File Paths
When building applications that involve user-uploaded content, such as photos, the decision of how to store that data—whether in a relational database or on the filesystem—is crucial. Many developers run into confusion when designing database schemas for file management. This post will walk you through the correct, scalable way to structure your Laravel migrations when handling multiple photo uploads, focusing specifically on how to manage the file paths correctly.
## The Golden Rule: Database vs. Filesystem Storage
The most important principle in handling media files is this: **you should rarely store large binary files directly inside your database tables.** Doing so leads to bloated queries, slower backups, and significantly increased database size.
Instead, the standard practice, especially within the Laravel ecosystem, is to use the filesystem (like the local disk or cloud storage like Amazon S3) to hold the actual photo files, and then store only the *reference*—the path or URL—in your database. This keeps your database lean, fast, and highly manageable.
## Structuring Your Photo Migration
Let’s address your specific question about the `src` field in your migration. You are correct to think about defining columns within the migration file, but the structure should focus on storing metadata, not the binary data itself.
When creating a table for photos, you need fields to store descriptive information (metadata) about the photo, and one field to store the location of the actual file.
Consider setting up your `photos` table migration:
```php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePhotosTable extends Migration
{
public function up()
{
Schema::create('photos', function (Blueprint $table) {
$table->id();
// The foreign key linking to the user who uploaded it
$table->foreignId('user_id')->constrained()->onDelete('cascade');
// This is the crucial field for storing the file path/name
$table->string('path'); // Stores the relative path on the disk or S3 URL
$table->string('filename'); // Optional: stores the original name if needed
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('photos');
}
}
```
Notice how we defined `path` and `filename` as `string()` types. This is where we store the *reference* to the file, not the photo data itself. If you were using a package like Spatie Media Library, this structure would be even more streamlined, leveraging Eloquent relationships effectively, which is a core strength of the Laravel framework, as seen on the official site: https://laravelcompany.com.
## Implementing the Storage Logic in Laravel
Once the migration is set up, the next step is handling the actual file upload process within your controller and model logic. This involves using Laravel's built-in `Storage` facade to manage where the files are physically saved.
Here is a simplified conceptual flow:
1. **Upload:** The user sends the image via an HTTP request to your controller.
2. **Store File:** In the controller, you use the `request()->file('photo')->storeAs('photos', $file)` method (or similar) to save the actual file to a designated directory on your server (e.g., `storage/app/public/photos`).
3. **Record Path:** After a successful save, the controller retrieves the path where the file was saved and saves *that path* into your database record using Eloquent:
```php
// In your PhotoController.php
use App\Models\Photo;
use Illuminate\Support\Facades\Storage;
// ... inside the upload method
$path = $request->file('photo')->store('photos', 'public'); // Saves file to storage/app/public/photos/...
Photo::create([
'user_id' => auth()->id(),
'path' => $path, // Storing the relative path in the DB
]);
```
By separating the concerns—using the filesystem for the heavy lifting and the database for relational data—you create an architecture that is robust, performant, and adheres to best practices. This separation allows you to easily scale your application without compromising data integrity.
## Conclusion
Sticking to the principle of storing file references in the database rather than the files themselves is fundamental to scalable Laravel development. By correctly structuring your migration to define fields for paths and leveraging Laravel's Storage capabilities, you ensure that your application remains fast, maintainable, and reliable. Always prioritize clean separation between data storage and file storage when managing user-uploaded assets.