Amazon S3
AWS S3 (and any S3-compatible bucket). Uses the standard AWS credential chain - environment, IAM role, shared profile.
Installation
@aws-sdk/client-s3, @aws-sdk/s3-presigned-post, and @aws-sdk/s3-request-presigner are optional peer dependencies of files-sdk - install alongside the SDK so the adapter’s imports resolve at runtime.
npm install files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presignerpnpm add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presigneryarn add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presignerbun add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presignernub add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presigneraube add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presigner@aws-sdk/lib-storage is optional too. Install it to report true byte-level upload progress via onProgress, to use multipart, or to upload a ReadableStream body of unknown length. It’s only loaded when upload uses onProgress, multipart, or a ReadableStream body of unknown length.
On Cloudflare Workers and other edge runtimes without a DOMParser, @aws-sdk/client-s3’s XML parsing fails at runtime. Use s3Fetch() from files-sdk/s3-fetch there instead — the same S3 protocol over a SigV4-signed fetch, with no @aws-sdk/* packages.
Usage
import { Files } from "files-sdk";
import { s3 } from "files-sdk/s3";
const files = new Files({
adapter: s3({
bucket: "uploads",
region: "us-east-1",
// credentials auto-loaded from the AWS chain
// (env vars, IAM role, shared profile, ...)
}),
});
Canonical AWS S3 buckets support provider-native conditional create, replace, exact read, delete, and copy. Conditional copy sends its source ETag and destination create/replace predicate in one CopyObject request.
The primitives are exposed only when the client will talk to canonical AWS: no endpoint option and no AWS_ENDPOINT_URL_S3 / AWS_ENDPOINT_URL redirect in the environment (the AWS SDK honors those on its own). A shared-config endpoint_url — profile-level or under a services section — is invisible at construction, so it is caught at request time instead: a conditional request whose resolved hostname is not under amazonaws.com (or amazonaws.com.cn in the China regions) fails closed before it is sent. S3-compatible services differ in conditional-header support, so in every one of those cases the adapter refuses rather than risk an unconditional overwrite. AWS-hosted endpoints (VPC, FIPS, dual-stack, GovCloud) resolve under amazonaws.com and need no override. Pass conditional: true to opt an S3-compatible endpoint you have verified back in (it skips both checks), or conditional: false to disable the primitives on a canonical bucket.
Conditional copy needs @aws-sdk/client-s3 3.919.0 or newer, where CopyObject gained IfMatch / IfNoneMatch (the peer range now starts at 3.1079.0). Because an optional peer range is advisory, the adapter also verifies at request time that every predicate it set was actually serialized as a header and rejects the call if the installed client dropped one. Conditional uploads take a buffered body (Blob, Uint8Array, ArrayBuffer, or string) — a stream is rejected before I/O.
Options
bucketstring
S3 bucket name. The adapter scopes all operations to it.
stringregion?string
AWS region the bucket lives in (e.g. `us-east-1`). Falls back to `AWS_REGION`, then `AWS_DEFAULT_REGION`; required if neither is set.
stringendpoint?string
Override the S3 service endpoint. Use this to point at S3-compatible services (DigitalOcean Spaces, Wasabi, Backblaze B2, LocalStack, etc.). With an explicit endpoint the client sends request checksums, and validates response checksums, only when the operation requires them (`requestChecksumCalculation` / `responseChecksumValidation` set to `"WHEN_REQUIRED"`), because several S3-compatible services reject the `x-amz-checksum-crc32` header newer SDKs add by default. Set `AWS_REQUEST_CHECKSUM_CALCULATION` / `AWS_RESPONSE_CHECKSUM_VALIDATION` to override.
stringforcePathStyle?boolean
Use path-style addressing (`https://endpoint/bucket/key`) instead of virtual-hosted style (`https://bucket.endpoint/key`). Required by some S3-compatible services and by LocalStack.
booleanconditional?boolean
Whether to expose the native conditional primitives (`If-Match` / `If-None-Match` create, replace, exact read, delete, and copy). Defaults to `true` only when the client will talk to canonical AWS S3: no `endpoint` here and no `AWS_ENDPOINT_URL_S3` / `AWS_ENDPOINT_URL` redirect in the environment. S3-compatible services differ in which conditional headers they honor, so the adapter fails closed for them rather than risk an unconditional overwrite. A shared-config `endpoint_url` (profile- or service-level) is invisible at construction, so it is caught at request time instead: a conditional request whose resolved hostname is not `amazonaws.com` or `amazonaws.com.cn` (or a subdomain of either) fails closed before it is sent. AWS-hosted endpoints (VPC, FIPS, dual-stack, GovCloud, the China regions) all resolve under those suffixes and need no override. Set `true` to opt an S3-compatible endpoint that you have verified honors `If-Match` / `If-None-Match` in — this skips both the constructor check and the request-time hostname check — or `false` to disable the primitives on a canonical bucket.
booleancredentials?{
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
}
Static credentials. Skip to use the AWS credential chain (env vars, IAM role, shared profile, EC2/ECS/EKS instance metadata).
{
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
}publicBaseUrl?string
Origin used to build URLs from `url()`. When set, `url(key)` returns `${publicBaseUrl}/${key}` and skips signing — appropriate for buckets fronted by a CDN, public-read policy, or custom domain. When unset, `url()` falls back to a presigned `GetObject` URL (see {@link defaultUrlExpiresIn}). A trailing slash on the base is tolerated. Each key segment is URL-encoded (the `/` separators are kept), so pass raw keys; a pre-encoded key would be double-encoded.
stringdefaultUrlExpiresIn?number
Default expiry, in seconds, for the presigned URLs returned by `url()` when `publicBaseUrl` is not set. Defaults to 3600 (1 hour). Per-call `url(key, { expiresIn })` overrides.
numberdefaultProviderMessage?string
Override the fallback message used when an unknown error has no `message` of its own, and the label on the adapter's own errors. Internal — set by the S3-compatible wrappers (r2, minio, wasabi, …) so their users see "R2 error" instead of "S3 error".
stringdefaultProviderMessage is internal: the S3-compatible wrappers set it so their errors read “Wasabi error” rather than “S3 error”. You don’t need to pass it.
Limits
These come from S3 itself, so they apply to s3Fetch() and every S3-compatible wrapper as well:
- Presigned URLs live at most 7 days. SigV4 caps a presigned URL at 604800 seconds, so
url()and a presigned-PUTsignedUploadUrl()(nomaxSize) throw aProvidererror for a longerexpiresIn(ordefaultUrlExpiresIn) instead of returning a URL the server would reject.capabilities.signedUrl.maxExpiresInreports the ceiling. ApublicBaseUrllink has no expiry, so the cap doesn’t apply to it. copy()andmove()top out at 5 GB. Both are a single server-sideCopyObjectrequest, which S3 limits to 5 GB source objects; a larger copy fails. For bigger objects, stream adownload()into amultipartupload()(this adapter, not the fetch engine, which has no multipart) and thendelete()the source.- Resumable (
control) uploads fit the 10,000-part limit. An S3 multipart upload holds at most 10,000 parts, so for a large body the adapter raises the part size abovemultipart.partSize(up to S3’s 5 GiB part maximum) until the body fits. The chosen size is pinned in the resume token.
S3-compatible endpoints and checksums
Recent @aws-sdk/client-s3 versions add an x-amz-checksum-crc32 header to every PutObject and UploadPart (and a matching parameter to presigned PUT URLs), and some S3-compatible services reject it. When you pass an endpoint, the adapter sets requestChecksumCalculation and responseChecksumValidation to "WHEN_REQUIRED", so checksums are only sent and checked where an operation requires one. DeleteObjects still carries one, because S3 requires it. Set AWS_REQUEST_CHECKSUM_CALCULATION / AWS_RESPONSE_CHECKSUM_VALIDATION to override. Canonical AWS (no endpoint) keeps the SDK default.
Compatibility
| Method | Status | Notes |
|---|---|---|
upload |
✅ | |
download |
✅ | |
delete |
✅ | |
list |
⚠️ | The S3 list API returns no per-object Content-Type, so type is inferred from the key’s extension (application/octet-stream when unknown). Use head() for the stored value. |
search |
✅ | |
head |
✅ | |
exists |
✅ | |
copy |
✅ | Server-side CopyObject, limited to 5 GB source objects (see Limits). |
url |
✅ | Presigned URLs are capped at 7 days (see Limits). |
signedUploadUrl |
✅ | |
| conditional operations | ✅ | Single-object native requests. Bulk, multipart, resumable, and custom-endpoint conditionals are unsupported. |