Master scalable file uploads in Laravel. Learn to stream directly to S3 and process heavy files asynchronously to keep your application fast and memory-efficient.
Previously in this course, we explored testing DDD components to ensure our business logic remains predictable and isolated. This lesson shifts our focus to infrastructure concerns, specifically handling high-volume, large-file I/O without blocking our PHP workers or exhausting server memory.
When building a high-traffic SaaS platform, treating file uploads as simple request-response cycles is a recipe for disaster. If you've previously followed our beginner's guide to file uploads, you know the basics; now, we're moving into production-grade architecture where Storage, S3, and Performance are the primary constraints.
The biggest bottleneck in file handling isn't the storage medium itself—it's the PHP execution lifecycle. When you upload a 500MB file through a standard controller, you are effectively holding a worker process hostage while the binary data travels from the user's browser, through your load balancer, into PHP memory, and finally to your storage driver.
To scale, we must decouple the transport from the processing.
Instead of routing binary data through your application server, we leverage S3 Pre-signed URLs. This allows the client to upload directly to your S3 bucket. Your Laravel application merely orchestrates the permission, keeping the web server's I/O overhead near zero.
Once the file is in S3, we trigger an asynchronous event. Whether it's virus scanning, image optimization, or metadata extraction, this work must happen in a background queue. This keeps the user's request cycle responsive, even for massive files.
We'll implement a secure upload flow using Pre-signed URLs.
In your UploadService, generate a URL that allows the client to PUT the file directly to your bucket.
PHPnamespace App\Modules\Storage\Services; use Illuminate\Support\Facades\Storage; class UploadService { public function getPresignedUrl(string $path): string { #6A9955">// We define a 10-minute window for the upload return Storage::disk('s3')->temporaryUploadUrl( $path, now()->addMinutes(10) ); } }
The frontend receives this URL and uses the browser's fetch API to push the file. Because the request goes straight to AWS, your Laravel server isn't waiting for the stream to finish.
Once the upload completes, the client hits an endpoint to notify your system. Your controller shouldn't process the file; it should only dispatch a job.
PHP#6A9955">// In your Controller public function finalize(Request $request) { $request->validate(['file_path' => 'required|string']); #6A9955">// Dispatch to a high-priority queue specifically for I/O ProcessUploadedFile::dispatch($request->file_path) ->onQueue('file-processing'); return response()->json(['message' => 'Processing started']); }
filesystems.php to use the s3 driver with the league/flysystem-aws-s3-v3 package.GenerateUploadUrlAction that returns a signed URL for a specific user-owned directory.ProcessUploadedFile job that uses Storage::disk('s3')->get($path) to pull the file into a temporary local path for processing (e.g., using Intervention Image or FFmpeg).file_get_contents(). Always use streams (fopen and stream_copy_to_stream) to process files in chunks.file-processing) and assign it a specific worker pool so that long-running file tasks don't delay transactional emails or API responses.Handling large files effectively requires moving away from the synchronous request-response model. By using S3 pre-signed URLs, you remove your application from the data path, and by offloading file logic to background queues, you maintain sub-millisecond response times for your API.
Next, we will look at how to optimize the delivery of these assets to the end user by integrating robust caching and versioning strategies.
Up next: Optimizing Asset Pipelines
Master Laravel queue worker prioritization by implementing named queues. Learn to isolate critical tasks from background jobs for a scalable, responsive system.
Read moreMaster SQL indexing for joins by learning to analyze execution plans and build covering indexes that eliminate table scans in high-traffic Laravel applications.
Handling Large File Uploads
Custom Middleware Development
Database Connection Pooling
Handling Large Data Exports
Security Header Configuration
Database Sharding Concepts
Real-time Data Synchronization
Database Deadlock Prevention
Managing Third-Party API Integrations