Drupal sites accumulate media faster than anything else on the platform, and local disk is the wrong place for it at scale. Moving files to Amazon S3 gives you effectively unlimited storage, takes media off your application servers, and makes horizontal scaling possible without a shared filesystem. This guide walks through the integration end to end.

Why Use Amazon S3 with Drupal?

For storage scale and server independence, not for raw speed. That distinction matters, and it is worth being precise about before you scope the work.

Integrate Amazon S3 with Drupal

Amazon Simple Storage Service (S3) is a cloud object storage service from Amazon Web Services. Pairing it with Drupal moves your file assets off the application server and into object storage that scales independently of your hosting.

Three benefits are real and worth the setup:

  1. Scalability. S3 grows with your media library without a disk resize or a shared filesystem between web nodes. On a multi-server Drupal deployment this is often the reason to adopt it, not a side benefit.
  2. Server independence. Files no longer live on the machines serving your site, so you can scale web nodes horizontally, rebuild them, or replace them without migrating a files directory.
  3. Durability and access control. S3 provides versioning, server-side encryption, and granular access policies that a local files directory does not.

On performance, be precise: S3 by itself is object storage, not a content delivery network. Moving files to S3 removes load from your web servers, but a request from a user in Europe to a bucket in us-east-1 can be slower than serving that file locally. If latency is your goal, put CloudFront (or another CDN) in front of the bucket and serve media through the CDN domain. S3 solves the storage problem; the CDN solves the distance problem.

Need a Reliable Support Partner? Let's Talk.

Get a Free Consultation

How Do You Integrate Amazon S3 with Drupal?

Through the S3 File System (s3fs) module, in six steps. Steps 1 to 3 happen in AWS, steps 4 to 6 in Drupal. The module handles storing and serving Drupal site assets, including images, videos, audio, and other file types, from an S3 bucket.

Step 1: Create Your AWS Account

Visit the AWS homepage and follow the sign-up instructions. After creating your account, you will have access to the AWS Management Console, where you can create your S3 bucket.

Step 2: Create the S3 Bucket

  1. Log in to your AWS Management Console.
  2. Go to the S3 service page.
  3. Click Create bucket.
  4. Enter a unique name for your bucket. Bucket names are globally unique across all AWS accounts, so include your project name.
  5. Select the region where you want your bucket located. Choose the region closest to your hosting, not to your users, since a CDN will handle user proximity.
  6. Choose the default settings, or customize them to meet your specific needs.
  7. Click Create bucket.

Step 3: Create a Scoped IAM User

Do not use root account credentials for this. Create a dedicated IAM user whose permissions are limited to the single bucket Drupal will use, and generate the access key against that user. If the key is ever exposed, the blast radius is one bucket rather than your entire AWS account.

A minimal policy grants read, write, delete, and list on that bucket only:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::YOUR-BUCKET-NAME"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:PutObjectAcl",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
    }
  ]
}

Adjust to your environment. Some setups will need additional actions, and if your hosting runs on EC2 or ECS you can skip static keys entirely by attaching an IAM role to the instance.

Step 4: Install and Configure the s3fs Module

  1. Install the S3 File System module with Composer, then enable it.
  2. Configure it at /admin/config/media/s3fs, or in settings.php:

    // S3FS settings
    $settings['s3fs.access_key'] = getenv('S3FS_ACCESS_KEY');
    $settings['s3fs.secret_key'] = getenv('S3FS_SECRET_KEY');
    $config['s3fs.settings']['bucket'] = 'S3 BUCKET NAME';
    $config['s3fs.settings']['region'] = 'S3 BUCKET REGION';  // For example: us-east-1
    $settings['s3fs.use_s3_for_public'] = TRUE;  // Only if you want ALL public files on S3
  3. Verify the module is working by navigating to Configuration > Media > File system and checking that the S3 file system is listed as a download method.

Never hardcode the keys. Read them from environment variables, as above, or from a settings.local.php that is excluded from version control. An AWS access key committed to a repository is a credential leak, and public repositories are scanned for exactly this pattern within minutes. If a key has already been committed, rotate it in IAM rather than deleting the commit.

Each S3 bucket has its own access key, secret key, name, and region. On a team, these are normally provisioned by whoever owns the AWS account, such as your DevOps engineers, and delivered through a secrets manager rather than over chat or email.

Step 5: Configure Upload Fields

To route a specific field to S3, navigate to the content type that has the upload field, click the Manage fields tab, and click Edit next to the field. Change the Upload destination option to the S3 file system.

Once the module is enabled, two new download methods appear in the Drupal file system settings at /admin/config/media/file-system, where you can set the site's default download method:

Configuring upload fields in Amazon S3

In the screenshot below, a specific media field is configured to be managed by S3 File System rather than the site default:

Amazon S3 field setting

To verify, confirm the images render correctly and then inspect the image source in the browser. It should show an external path beginning with https://BUCKET-NAME.s3.amazonaws.com/, or your CloudFront domain if you have configured one.

Step 6: Configure S3 for Private Files

While s3fs is primarily used for a site's public files, private files can be stored on S3 too. Certain media that should only be accessible to authenticated users or site administrators may need to live in the bucket while remaining access-controlled.

Enable the private files options on the module settings page, or add these two lines to settings.php:

$settings['s3fs.use_s3_for_private'] = TRUE; // Use S3 for private files
$settings['s3fs.upload_as_private'] = TRUE;  // Upload files as private

With these settings, files uploaded to the private file system are served through the site URI rather than directly from the bucket, so Drupal's access checks still apply. Confirm this after configuration by copying a private file's direct S3 URL and requesting it while logged out. It should be refused.

If you have a separate S3 bucket for testing, override the module settings in your site's settings.local.php. Keeping non-production environments on their own bucket prevents a staging test from overwriting production media.

Should You Route All Files to S3, or Just Specific Fields?

Field level, in most cases. Setting use_s3_for_public to TRUE sends everything to S3, including your aggregated CSS and JavaScript, which are the assets most sensitive to latency and the ones your webserver already handles well.

 All public files on S3Field-level configuration
What movesEverything, including aggregated CSS and JSOnly the fields you designate
Theme asset latencyAdds a round trip to S3 for every page renderServed locally at webserver speed
Where it's setOne line in settings.phpPer field, under Manage fields
Setup effortLowestHigher, and grows with the content model
Best forMulti-server deployments with no shared filesystem, where local disk is not an optionMost sites, especially media-heavy ones on single-server or managed hosting

The recommendation: keep the default download method as Public local files served by the webserver, and configure S3 at the field level for the media that actually needs it. Your CSS and JS stay local with lower latency, and your image and video libraries move off local disk. Go global only when a shared filesystem is genuinely unavailable across your web nodes.

What Goes Wrong, and How Do You Fix It?

Three problems account for most s3fs support threads.

Images Upload Successfully but Render as Broken

Usually a permissions mismatch between the IAM policy and how the module writes objects, or a bucket-level public access block preventing reads. Check the IAM policy includes s3:PutObjectAcl, and confirm the bucket's public access settings match the way you intend files to be served. If you are serving through CloudFront, verify the distribution's origin access configuration rather than the bucket policy alone.

Files Exist in the Bucket but Drupal Cannot See Them

s3fs keeps a local metadata cache of bucket contents so it does not have to query S3 on every file operation. Files added to the bucket outside Drupal, or a migration that wrote directly to S3, will not appear until that cache is refreshed. The module ships a Drush command for this; check drush list | grep s3fs for the exact syntax on your version. Run it after any bulk operation that touched the bucket directly.

Everything Works Locally and Fails on Production

Almost always an environment variable that was set in one place and not the other. Confirm the credentials are actually present in the production environment, and that the region matches the bucket. A region mismatch produces an authentication-style error that looks like a credentials problem and is not.


What Should You Do Next?

Decide on field-level or global before you install anything, because reversing that choice later means re-pointing existing file references. For most sites the sequence is: create the bucket, scope an IAM user to it, install s3fs, configure the media fields that carry the bulk of your storage, then add CloudFront if latency rather than storage was the original problem.

Vardot builds and maintains enterprise Drupal platforms as a Drupal Diamond Certified Partner, with 200+ platforms launched and a 4.9/5 Clutch rating across verified reviews. If you are planning an S3 migration for an existing media library, the file reference migration is usually the part that needs the most planning, and it is worth scoping before the module goes in.

Planning an S3 migration for an existing Drupal media library?

Talk to Our Drupal Team

Amazon S3