Limitations
Oyster implements the most commonly used S3 operations. Some features and behaviors differ from a full AWS S3 deployment.
Which S3 features does Oyster support?
| Feature | Status | Notes |
|---|---|---|
| CreateBucket | Supported | |
| HeadBucket | Supported | |
| ListBuckets | Supported | Max 1000, no pagination |
| DeleteBucket | Supported | Requires empty bucket (same as AWS S3) |
| PutObject | Supported | Single-part only, max 1GB |
| GetObject | Supported | |
| HeadObject | Supported | |
| DeleteObject | Supported | |
| ListObjectsV2 | Supported | Prefix, delimiter, pagination |
| Conditional requests | Supported | If-Match, If-None-Match on PutObject, GetObject, and HeadObject; DeleteObject supports If-Match only |
| Multipart upload | Not supported | Use single PutObject (max 1GB) |
| CopyObject | Not supported | Download and re-upload instead |
| DeleteObjects (batch) | Not supported | Delete one at a time |
| Object versioning | Not supported | Overwrite replaces the object |
| Bucket policies | Not supported | |
| ACLs | Not supported | |
| CORS | Not supported | |
| Server-side encryption | Not supported | Oyster stores data unencrypted |
| Object tagging | Supported | get/put/delete; shares tags with JSON API |
| Custom metadata headers | Not supported | Oyster stores only Content-Type |
| Website hosting | Not supported | |
| S3 Select | Not supported | |
| Storage classes | Not supported | All objects are STANDARD |
| Transfer Acceleration | Not supported | |
| Inventory and Analytics | Not supported | |
| Object Lock and Legal Hold | Not supported | |
| Lifecycle rules | Not supported | See Object expiration |
How does Oyster behave differently from AWS S3?
Object expiration
All objects in a bucket share the owning account's StoragePool
lifetime, with no per-object expiration to set. Oyster runs a
background extension service that renews the pool before it expires,
so objects persist indefinitely as long as the service is running and
the account's wallet stays funded. See
Blob Lifecycle for the model.
Bucket naming
Oyster's bucket naming rules are slightly stricter than AWS S3:
| Rule | AWS S3 | Oyster |
|---|---|---|
Dots (.) in names | Allowed | Not allowed |
Underscores (_) in names | Allowed | Not allowed |
Consecutive hyphens (--) | Allowed | Not allowed |
| Reserved names | None | health, ready, metrics, api |
ListBuckets limit
ListBuckets returns a maximum of 1000 buckets with no pagination support.
Path-style URLs only
Oyster only supports path-style S3 URLs:
http://endpoint/bucket-name/key
Oyster does not support virtual-hosted-style URLs (bucket-name.endpoint/key).
Always set force_path_style: true in your SDK configuration. For full client setup, see S3 setup.
No region semantics
Oyster ignores the region in S3 requests. Oyster stores all data in the same
location. You still need to specify a region for SigV4 signing to work, so
use any valid region string, for example us-east-1.
ETag format
ETags are always the MD5 digest of the object content, even for large objects. There is no multipart ETag format, because Oyster does not support multipart upload.
Conditional request headers
Oyster supports If-Match and If-None-Match headers on PutObject,
GetObject, HeadObject, and DeleteObject (If-Match only). These enable
cache validation (If-None-Match returns 304 on GET or HEAD) and safe
concurrent writes (If-Match for optimistic locking, If-None-Match: *
for create-only semantics). Oyster does not support time-based conditionals (If-Modified-Since,
If-Unmodified-Since).
How to set path-style URLs in the Rust SDK
In the AWS SDK for Rust (aws-sdk-s3), call force_path_style(true) on the config builder. The following client configuration also sets the region and endpoint:
use aws_sdk_s3::config::{Credentials, Region};
let creds = Credentials::new(
"OYAK1234567890ABCDEF",
"abcdef1234567890...",
None, None, "oyster",
);
let config = aws_sdk_s3::Config::builder()
.behavior_version_latest()
.region(Region::new("us-east-1"))
.endpoint_url("http://localhost:3000")
.credentials_provider(creds)
.force_path_style(true)
.build();
let client = aws_sdk_s3::Client::from_conf(config);
Other SDKs expose an equivalent path-style option. For full client setup, see S3 setup.