S3
PHP
file management
cloud storage
tutorial

How to move all files and folder from one folder to another of S3 bucket in php with some short way?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In Amazon S3, a “folder” is only a key prefix. That means moving one folder to another is really a per-object process: copy each object to a new key, then delete the old one after the copy succeeds.

There is no single atomic “move directory” API in S3, so the right PHP solution is to paginate through the source prefix, preserve each relative path, copy it, and only then delete the original key. Anything shorter than that is usually just hiding the same logic.

Understand What a Move Means in S3

Suppose your source prefix is from-folder/ and the destination prefix is to-folder/. If an object exists at:

from-folder/images/a.jpg

then the moved object should end up at:

to-folder/images/a.jpg

That “preserve the relative suffix” rule is the whole operation.

Two implementation rules matter:

  • Copy first.
  • Delete only after the copy succeeds.

If you delete first and then the copy fails, the data is gone.

Basic AWS SDK Setup in PHP

Install the AWS SDK for PHP:

bash
composer require aws/aws-sdk-php

Create the S3 client:

php
1<?php
2require 'vendor/autoload.php';
3
4use Aws\S3\S3Client;
5
6$s3 = new S3Client([
7    'version' => 'latest',
8    'region'  => 'us-east-1',
9]);
10
11$bucket = 'my-bucket';
12$sourcePrefix = 'from-folder/';
13$targetPrefix = 'to-folder/';

Use IAM roles or environment-based credentials instead of hardcoding keys into the script.

Move Objects with Pagination

For a real prefix move, use a paginator so large folders do not load into memory all at once.

php
1<?php
2use Aws\S3\S3Client;
3
4function movePrefix(S3Client $s3, string $bucket, string $sourcePrefix, string $targetPrefix): void
5{
6    $paginator = $s3->getPaginator('ListObjectsV2', [
7        'Bucket' => $bucket,
8        'Prefix' => $sourcePrefix,
9    ]);
10
11    foreach ($paginator as $page) {
12        foreach ($page['Contents'] ?? [] as $obj) {
13            $srcKey = $obj['Key'];
14            $relative = substr($srcKey, strlen($sourcePrefix));
15            $dstKey = $targetPrefix . $relative;
16
17            $s3->copyObject([
18                'Bucket' => $bucket,
19                'CopySource' => rawurlencode($bucket . '/' . $srcKey),
20                'Key' => $dstKey,
21            ]);
22
23            $s3->deleteObject([
24                'Bucket' => $bucket,
25                'Key' => $srcKey,
26            ]);
27        }
28    }
29}
30
31movePrefix($s3, $bucket, $sourcePrefix, $targetPrefix);

rawurlencode helps when keys contain spaces or special characters.

Add Safety Checks for Important Data

For high-value data, verify the destination object before deleting the source object.

php
1<?php
2function moveObjectSafe(S3Client $s3, string $bucket, string $srcKey, string $dstKey): void
3{
4    $s3->copyObject([
5        'Bucket' => $bucket,
6        'CopySource' => rawurlencode($bucket . '/' . $srcKey),
7        'Key' => $dstKey,
8    ]);
9
10    $s3->headObject([
11        'Bucket' => $bucket,
12        'Key' => $dstKey,
13    ]);
14
15    $s3->deleteObject([
16        'Bucket' => $bucket,
17        'Key' => $srcKey,
18    ]);
19}

That extra request is slower, but it is a good trade when correctness matters more than raw speed.

A dry-run mode is also worth having before large moves.

php
1$dryRun = true;
2
3if ($dryRun) {
4    echo "would move {$srcKey} -> {$dstKey}\n";
5}

Operational Concerns

The required permissions usually include:

  • 's3:ListBucket'
  • 's3:GetObject'
  • 's3:PutObject'
  • 's3:DeleteObject'

If bucket versioning is enabled, remember that deleting the source creates a delete marker rather than instantly erasing history. That is helpful for rollback, but you should still know exactly how the bucket’s retention policy behaves.

For very large moves, consider a two-phase process: copy everything first, validate, then delete sources afterward. It is slower but much safer during migrations.

Common Pitfalls

A common mistake is assuming S3 has a real folder move operation. It does not; folders are prefixes, not filesystem directories.

Another issue is listing only the first page of objects and accidentally moving part of the prefix while leaving the rest behind.

Developers also often forget to preserve the relative path under the source prefix. That can flatten nested content into one destination folder and destroy the intended layout.

Finally, never delete the source objects before a successful copy. That is the one mistake that turns a migration bug into data loss.

Summary

  • In S3, moving a folder means copying each object to a new prefix and deleting the old key.
  • Use ListObjectsV2 pagination so large prefixes are handled safely.
  • Preserve each object’s relative path under the source prefix.
  • Copy first and delete only after success, ideally with verification for important data.
  • Add dry-run, logging, and strong IAM boundaries before using the script in production.

Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design