upload a directory to s3 with boto
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Uploading a directory to S3 is really a loop over files plus a rule for turning local paths into S3 object keys. S3 does not store directories in the filesystem sense, so the job is to walk the local tree, preserve relative paths, and upload each file under a predictable key.
With boto3, the most practical method is upload_file, which handles multipart upload behavior for larger files and is easier to use than lower-level request APIs.
Walk the Local Directory Tree
The first step is to visit every file under the base directory:
This gives you every file, including nested ones. The important next step is to convert each file into a relative path so the S3 key does not accidentally include machine-specific absolute path segments.
Build Stable S3 Keys
Relative paths are the cleanest source for S3 keys:
If file_path is /tmp/site-assets/css/app.css and the base directory is /tmp/site-assets, the key becomes css/app.css. Adding a prefix such as deployments/current produces deployments/current/css/app.css.
Upload Each File with boto3
Now combine the directory walk and key builder:
That is enough for many backup, deployment, and asset-publishing workflows.
Add Metadata When Needed
If the uploaded files will be served directly from S3 or through CloudFront, content types matter. You can pass them through ExtraArgs:
Without the correct content type, browsers may download files instead of rendering them as HTML, CSS, JavaScript, or images.
Use the Standard Credential Chain
Do not hard-code AWS credentials in the script. boto3 already knows how to load credentials from:
- environment variables
- AWS shared credentials files
- IAM roles on AWS infrastructure
That means the same upload script can run locally and in CI without changing the code, as long as credentials are provided through standard AWS mechanisms.
Know What This Code Does Not Do
An upload loop only sends files to S3. It does not delete old objects that were removed locally. If you need true synchronization behavior, deletion has to be handled separately and very carefully.
That distinction matters because "upload directory" and "mirror directory" are not the same task.
Common Pitfalls
- Treating S3 keys as if they were real directories instead of object names with prefixes.
- Building keys from absolute paths and uploading unwanted machine-specific segments.
- Forgetting content types for web assets.
- Hard-coding AWS credentials in the script.
- Assuming upload-only code also deletes obsolete remote objects.
Summary
- Uploading a directory to S3 means walking files and mapping relative paths to object keys.
- Use
boto3.client("s3").upload_file(...)as the default upload primitive. - Preserve relative paths so the bucket layout stays predictable.
- Add metadata such as
ContentTypewhen files will be served directly. - Keep upload logic separate from deletion or sync logic.

