Learning objectives
After reading this article you will be able to:
- Understand what Amazon S3 is and how buckets, objects and keys work
- Know what it means for a service to be S3-compatible and where differences appear
- Connect an application to S3-compatible storage with boto3
Almost every project ends up storing files: profile pictures, attachments, exports, logs. Keeping them on the server's disk works until the first time you need to move machines, run more than one instance, or serve everything fast. That is where object storage comes in, and sooner or later someone says "just use S3".
S3 became so common that the name stopped meaning a single product. "S3" is also a way of talking to storage: an API that dozens of services implement. Understanding that difference keeps you from getting locked into one vendor and explains why the same code runs in very different places.
What is Amazon S3?#
Amazon S3 (Simple Storage Service) is AWS's object storage service. It stores data as objects inside buckets. An object is a file plus its metadata (such as Content-Type). A bucket is the container for objects. For the underlying concept, read what is object storage.
Every object has a key, its unique identifier inside the bucket. A key like photos/2026/cat.jpg looks like a folder path, but the storage is flat: photos/2026/ is just part of the name (a prefix). To see how this differs from disks and file shares, read object vs block vs file storage.
An object is addressable by a URL made of the endpoint, the bucket name and the key, for example https://my-bucket.s3.us-west-2.amazonaws.com/photos/cat.jpg. By default, buckets and objects are private: only someone who has been granted permission can access them.
A few numbers from the official documentation, worth double-checking before you depend on them:
- Designed durability of 99.999999999% (11 nines) and 99.99% availability over a year for S3 Standard, with copies across at least three Availability Zones.
- Objects up to 48.8 TiB, uploaded through multipart upload in up to 10,000 parts of 5 MiB to 5 GiB.
- Strong read-after-write consistency: after a successful PUT, any read or list sees the new data.
What does "S3-compatible" mean?#
S3 is accessed through a REST API over HTTP. Every SDK, the aws-cli and tools like rclone just build requests in that format and sign them with a key pair. If another service understands the same requests, it is S3-compatible.
In practice, switching providers becomes configuration:
- The endpoint changes: instead of
s3.amazonaws.com, the other service's address. - The access keys (access key and secret key) become the new service's.
- The upload, download, list and delete code stays the same.
That is why backup tools, CMSs, upload libraries and frameworks support S3 and, with no extra work, any compatible service. The reverse holds too: if you write your code against the S3 API, you can move providers without rewriting the application.
What differs between S3 and a compatible service?#
"Compatible" is not "identical". The S3 API is huge and each provider implements a subset. The core usually exists everywhere: create bucket, PutObject, GetObject, ListObjectsV2, DeleteObject, multipart upload and presigned URLs. These vary, so check the provider's documentation:
- Access control: S3 bucket policies, IAM and ACLs may be missing or behave differently.
- Advanced features: versioning, Object Lock, replication, event notifications and lifecycle rules.
- Regions and storage classes: a smaller provider may have a single region and a single class.
- Limits: maximum object size, minimum part size in multipart, number of buckets.
- Addressing: some services accept the bucket in the host (
bucket.endpoint), others only in the path (endpoint/bucket). - Checksums: recent AWS SDK versions started calculating checksums by default, and some compatible services do not accept that yet (see the example below).
How do you connect an app to S3-compatible storage?#
The example uses boto3, the AWS SDK for Python. Install it with pip install boto3. The endpoint and keys come from environment variables, never from the code.
import os
import boto3
from botocore.config import Config
s3 = boto3.client(
"s3",
endpoint_url=os.environ["S3_ENDPOINT"],
aws_access_key_id=os.environ["S3_ACCESS_KEY"],
aws_secret_access_key=os.environ["S3_SECRET_KEY"],
region_name=os.environ.get("S3_REGION", "us-east-1"),
config=Config(
# "path" puts the bucket in the URL path; "virtual" puts it in the host.
s3={"addressing_style": "path"},
# SigV4 signing, the current version, presigned URLs included.
signature_version="s3v4",
# Turns off the automatic checksums from boto3 1.36+ for services
# that do not accept them yet.
request_checksum_calculation="when_required",
response_checksum_validation="when_required",
),
)
bucket = os.environ["S3_BUCKET"]
s3.upload_file("report.pdf", bucket, "reports/2026/report.pdf") # upload
resp = s3.list_objects_v2(Bucket=bucket, Prefix="reports/") # list
for obj in resp.get("Contents", []):
print(obj["Key"], obj["Size"])
url = s3.generate_presigned_url( # temporary download link, 15 minutes
"get_object",
Params={"Bucket": bucket, "Key": "reports/2026/report.pdf"},
ExpiresIn=900,
)
print(url)Four things in here tend to cause trouble:
addressing_style: the default (auto) lets boto3 choose. Against AWS it usually picks the virtual style; with a customendpoint_url, current versions use path style. Settingpathexplicitly, as in the example, avoids surprises; if the provider requires the bucket in the host, usevirtual. The boto3 documentation describes the valuesauto,pathandvirtual.- Signature: in several cases boto3 still generates presigned URLs in the old format (SigV2).
signature_version="s3v4"forces SigV4, the current version, and many compatible services only accept that one. - Checksums: boto3 1.36 started calculating checksums on uploads by default. If your provider returns an error on
PutObject,when_requiredrestores the old behavior. If it accepts the new one, you can drop those two lines. - Region: compatible services usually ignore the region, but the SDK requires some value.
us-east-1is a common default.
The same applies to the aws-cli, which accepts --endpoint-url, and to rclone, which has an S3 remote type with an endpoint field. For temporary links, see what is a presigned URL. For large files, see how to upload large files.
When should you use S3 or a compatible service?#
S3-compatible storage fits user-uploaded images and videos, attachments, exports, data copies and the static files of a website. It fits poorly where you need ordinary file access, such as a database running on top of the disk, or small frequent writes to the same file: use a database or a block volume there. Also keep in mind that objects are replaced whole, not edited in place, and that latency is that of an HTTP request, not of a local disk.
When choosing between Amazon and a compatible service, compare the price of storage, requests and data transfer out (see what are egress fees), the region, and the features you actually use. If your code only uses the core of the API, switching later is cheap.
How to do this on Square Cloud#
Square Cloud Blob Storage is an S3-compatible service, and this article's code runs against it with configuration changes only, as the compatibility section described: S3_ENDPOINT=https://s3-blob.squarecloud.app, S3_REGION=auto and the S3 keys you derive from an API key in the "S3 access" tab of the dashboard. The same goes for the aws-cli with --endpoint-url, for rclone and for the AWS SDKs.
Before you migrate, check Blob against the list of what varies between providers. The endpoint supports List, Head, Get with Range, Put, Copy, Delete, multipart and SigV4 presigned URLs of up to 7 days. There are three fixed buckets per account: public, private and legacy (read-only). Since you can't create named buckets, set S3_BUCKET=public or private and organize files by prefix. Each object can be up to 10 GB, and multipart is only required above 100 MB. Beyond the S3 API, there is a REST API and a dashboard, with per-folder rules for visibility, expiration and caching.
On cost, there is no egress or ingress fee, and each plan includes a quota from 5 GB to 250 GB; S3 requests are rate-limited per plan. Durability is 99.999999999% (11 nines) with triple replication, and public files are served by a global CDN at the edge. Explore Blob Storage and compare quotas on Pricing.
Blob Storage
S3-compatible object storage with no egress fees
FAQs
Is S3 the same thing as object storage?
No. Object storage is the type of technology. S3 is the Amazon service that popularized it and, by extension, its HTTP API, which many other services copied.
Can I use the AWS SDK with a service that is not AWS?
Yes, if the service is S3-compatible. You point the SDK at the service's address (endpoint_url) and use its keys. The rest of your code stays the same.
Does S3-compatible mean it has every S3 feature?
No. Almost every compatible service covers the basics (upload, download, list, delete, multipart upload, presigned URLs). Advanced features such as bucket policies, Object Lock or event notifications vary by provider.
What is the maximum object size on Amazon S3?
48.8 TiB, uploaded in up to 10,000 parts of 5 MiB to 5 GiB each. Compatible services have their own limits, so check the provider's documentation.
More in Storage
See all 15 articles- What is a presigned (signed) URL?A presigned URL is a temporary link to a private file that works without login or credentials. See how it works, its limits and when to use it.
- What is object storage?Object storage keeps files as objects with a key and metadata, accessed over an HTTP API. See how it works, what it is for and where its limits are.
- Object lifecycle rules: expiring and cleaning up files automaticallyA lifecycle rule deletes files automatically after a set age. Learn how to create folder-level expiration rules on S3 with boto3 and how to verify they work.
- Public vs private files: buckets, temporary links and share linksA public file opens for anyone with the URL; a private one only through an authorized link. Learn how to choose, test access and share safely.