Php laravel Upload file directly to AWS S3 bucket

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Php Laravel: Uploading Files Directly to AWS S3 using Pre-signed URLs

As a senior developer working with modern web applications, we constantly face the challenge of handling large file uploads efficiently. When dealing with media files, relying solely on your application server (like PHP/Laravel) to handle massive data transfers can lead to timeouts, memory exhaustion, and poor scalability. The superior architectural pattern for this scenario is using Pre-signed URLs to allow the client (browser) to upload files directly to cloud storage like AWS S3.

This guide will walk you through exactly how to implement this highly efficient file transfer mechanism within a Laravel application.

Why Use Pre-signed URLs?

The traditional method involves the client sending the file to your Laravel server, which then reads the file and uploads it to S3. This burdens your web server with unnecessary bandwidth and processing.

Pre-signed URLs solve this by allowing AWS to generate a temporary, time-limited URL that grants direct write access to a specific S3 object or bucket. The client then bypasses your application entirely and streams the file directly to S3.

Key Benefits:

  1. Reduced Server Load: Your Laravel server only handles the initial request and authorization, not the massive file transfer.
  2. Improved Performance: Upload speeds are significantly faster as traffic flows directly between the client and S3.
  3. Enhanced Security: You maintain full control over which files can be uploaded via these signed links.

Implementation Steps in Laravel

Implementing this requires a few steps: setting up AWS credentials, authorizing the user/file, and generating the pre-signed URL on the server side before sending it to the client.

Step 1: Setup AWS Credentials and Configuration

Ensure your Laravel environment is configured to interact with AWS. Typically, you would use the AWS SDK for PHP or leverage packages that integrate well with Laravel's service container. For robust handling of file operations in a Laravel context, utilizing established patterns (as seen in best practices discussed at laravelcompany.com) is crucial for maintainability.

Step 2: Generating the Pre-signed URL

The generation process happens within your controller logic after the user has authenticated and you have verified they are authorized to upload a file. You will use the AWS SDK client to request S3 to generate this temporary link.

Here is a conceptual example of how you might generate an upload URL in a Laravel Controller:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Aws\S3\S3Client; // Assuming you are using the AWS SDK

class FileUploadController extends Controller
{
    protected $s3Client;
    protected $bucketName = 'your-s3-bucket-name';

    public function __construct(S3Client $s3Client)
    {
        $this->s3Client = $s3Client;
    }

    public function generatePresignedUploadUrl(Request $request, $fileName)
    {
        // 1. Verify user permissions (Crucial security step!)
        if (!$this->checkUserPermissions($request)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $key = 'uploads/' . $fileName; // Define the desired S3 path
        $bucket = $this->bucketName;

        try {
            // 2. Generate the signed URL for PUT operation
            $command = $this->s3Client->createPresignedRequest(
                'putObject',
                [
                    'Bucket' => $bucket,
                    'Key'    => $key,
                    'Expires' => '+7 days', // URL is valid for one week
                ]
            );

            $url = (string) $command->getUri();

            return response()->json([
                'upload_url' => $url,
                'file_name' => $fileName
            ]);

        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to generate URL'], 500);
        }
    }
}

Step 3: Client-Side Upload

Once the Laravel backend returns the $url, your frontend JavaScript handles the actual file transfer using a standard fetch or XMLHttpRequest. The client will use this URL in a PUT request, sending the raw file data directly to S3.

// Example conceptual client-side logic (JavaScript/Frontend)
async function uploadFile(url, fileData, fileName) {
    const response = await fetch(url, {
        method: 'PUT',
        headers: {
            // IMPORTANT: Headers must match what S3 expects for the PUT operation
            'Content-Type': fileData.type 
        },
        body: fileData
    });

    if (response.ok) {
        console.log('File uploaded successfully to S3!');
    } else {
        console.error('Upload failed:', response.statusText);
    }
}

Conclusion

Using Pre-signed URLs is not just a convenience; it is a fundamental shift towards building scalable, high-performance applications by offloading heavy data transfer tasks to specialized services like AWS S3. By correctly implementing the authorization checks on the Laravel side and relying on established SDK patterns, you can achieve extremely fast and secure file uploads, making your application robust and ready for growth.