Skip to content

FRD: Storage Provider Real Implementation

FieldValue
IDFRD-044
OwnerDavid Holmes
StatusDraft
Last Updated2026-06-02
Open Source Libraries@aws-sdk/client-s3, @aws-sdk/s3-request-presigner
DocumentationAWS SDK v3 S3 Client · S3 API Reference · Pre-signed URLs
RelatedADR-027 (Default Tech Stack), ADR-014 (Open Source First)
Target Releasev2.1.0
TypeLibrary
ComplexityM

Document Summary

This FRD defines the work to ship @dmwd-io/storage as an optional package that re-exports @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner as the platform standard for S3-compatible file storage via AWS SDK v3. Per ADR-014 (Open Source First), the value delivered is standards and drift prevention — not a custom abstraction. Platform conventions (env var names, defaults) are layered on top of the library’s own API.


Introduction

Overview

Per ADR-014, @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner are designated as the platform community library for S3-compatible file storage. Rather than building a custom StorageProvider interface, this FRD ships @dmwd-io/storage as a thin re-export of those libraries with platform conventions documented alongside. The canonical env var names (S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) are the platform standard — consuming applications configure the AWS SDK directly using these variables.

Goals

  • Designate @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner as the platform standard for S3-compatible file storage.
  • Re-export both libraries via @dmwd-io/storage so consumers have a single platform import.
  • Document S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY as the canonical platform env var names.
  • Provide pre-signed URL generation for secure, time-limited direct access (via the library’s own getSignedUrl).

Non-Goals

  • CDN configuration or edge caching.
  • Image processing or thumbnail generation.
  • Building a custom provider interface or adapter layer — the library’s own API is the interface (per ADR-014).

Scope

In Scope

ItemDescription
packages/@dmwd-io/storage/src/index.tsRe-export @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner.
packages/@dmwd-io/storage/package.jsonPackage manifest with peer dependencies on both AWS SDK v3 packages.
Platform env var documentationDocument S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY as canonical names.
.env.exampleAdd the canonical env var names.

Out of Scope

ItemReason
Custom StorageProvider interfaceADR-014: library’s own API is the interface.
Azure Blob Storage adapterNo current requirement.
GCS adapterNo current requirement.
Multipart upload resumptionComplex; deferred to follow-up if large file uploads become a need.

Users and Pain Points

UserPain Point
Application developerNo platform standard for S3 storage means teams make inconsistent choices about SDK usage and env var names.
Platform maintainerNo designated library means drift across apps using different AWS SDK versions or configuration patterns.
OperationsNo standardized env var names means inconsistent bucket naming and credential configuration across apps.

Definitions

TermDefinition
@dmwd-io/storageThe platform thin re-export package for S3-compatible file storage.
S3-compatibleAny object storage service that implements the AWS S3 API (AWS S3, MinIO, DigitalOcean Spaces, Cloudflare R2).
Pre-signed URLA time-limited URL that grants temporary access to a private object without requiring credentials.

Current State

Applications needing file storage call the AWS SDK directly without a platform-designated standard. There is no canonical set of env var names, no shared package, and no documented convention for MinIO vs. AWS S3 endpoint configuration. Teams make independent choices, leading to drift.


Proposed Solution

@dmwd-io/storage re-export package

Create packages/@dmwd-io/storage with a single entry point:

// packages/@dmwd-io/storage/src/index.ts
export * from '@aws-sdk/client-s3';
export * from '@aws-sdk/s3-request-presigner';

Consumers import from the platform package:

import { S3Client, PutObjectCommand, GetObjectCommand } from '@dmwd-io/storage';
import { getSignedUrl } from '@dmwd-io/storage';

No custom interface is built — the library’s API is the interface.

Platform env var conventions

The following env var names are the platform standard for all apps using @dmwd-io/storage:

Env VarPurpose
S3_BUCKETTarget bucket name.
S3_REGIONAWS region (e.g. us-east-1).
AWS_ACCESS_KEY_IDAWS access key (standard AWS env var name).
AWS_SECRET_ACCESS_KEYAWS secret key (standard AWS env var name).
S3_ENDPOINTOptional. Override for MinIO, R2, or Spaces.

For MinIO local dev, set S3_ENDPOINT to the MinIO instance URL (e.g. http://localhost:9000). The AWS SDK’s endpoint config option accepts this directly.


Requirements

IDPriorityRequirement
STOR-01P0@dmwd-io/storage re-exports @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner.
STOR-02P0Platform env var names (S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) are documented and added to .env.example.
STOR-03P0Package uses peer dependencies so applications control the AWS SDK version.
STOR-04P1S3_ENDPOINT is documented as the optional override for MinIO/R2/Spaces.

Functional Requirements

  1. import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, ListObjectsV2Command } from '@dmwd-io/storage' resolves to the @aws-sdk/client-s3 equivalents.
  2. import { getSignedUrl } from '@dmwd-io/storage' resolves to the @aws-sdk/s3-request-presigner equivalent.
  3. The package adds no runtime logic — it is a pure re-export.
  4. Consuming applications construct S3Client directly using the platform env var names.

Non-Functional Requirements

CategoryRequirement
Dependency sizeNo additional runtime overhead — re-export only. @aws-sdk/client-s3 (modular SDK v3) is ~50 kB.
SecretsAWS credentials passed via environment variables. Never logged. Canonical names documented in .env.example.
VersioningAWS SDK packages are peer dependencies. Applications pin the version they need.

API/Interface Requirements

The library’s own API is the interface. No custom types are defined in @dmwd-io/storage. Consumers use the AWS SDK v3 API directly:

import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand } from '@dmwd-io/storage';
import { getSignedUrl } from '@dmwd-io/storage';
const client = new S3Client({
region: process.env.S3_REGION,
endpoint: process.env.S3_ENDPOINT, // optional, for MinIO/R2
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
});

Accessibility Requirements

Not applicable. This is a headless library with no UI surface.


Content and Documentation Requirements

  • Document S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and S3_ENDPOINT as the canonical env var names.
  • Add all five env var names to .env.example.
  • Add a usage example showing how to construct S3Client using the platform env vars.
  • Note MinIO local dev configuration (set S3_ENDPOINT to the MinIO instance URL).

Dependencies

DependencyTypeNotes
@aws-sdk/client-s3Peer (npm)AWS SDK v3 S3 client. Modular, ~50 kB.
@aws-sdk/s3-request-presignerPeer (npm)Pre-signed URL generation. ~10 kB.
ADR-014GovernanceOpen Source First principle.
ADR-051GovernanceProvider pattern architecture.

Risks and Tradeoffs

RiskLikelihoodImpactMitigation
AWS SDK v3 has breaking changes between minor versions.LowMediumPeer dependency lets applications pin to a specific minor version range.
MinIO endpoint configuration differs across environments.MediumLowS3_ENDPOINT is the canonical override. Document common MinIO local dev setup.
Large file uploads may time out without multipart support.MediumMediumAWS SDK v3 natively supports multipart upload. No custom adapter needed.

Open Questions

  1. Should @dmwd-io/storage also re-export @aws-sdk/lib-storage (the managed multipart upload helper)? Leaning toward yes to keep the platform import consistent.
  2. Should we publish a recommended createS3Client(env) helper that reads from the canonical env vars? Leaning toward deferring — the env vars are documented and the pattern is simple.
  3. Should delete() accept an array of keys for batch deletion? Leaning toward deferring — the AWS SDK’s DeleteObjectsCommand is available directly.

Acceptance Criteria

  • packages/@dmwd-io/storage/src/index.ts re-exports @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner.
  • import { S3Client, PutObjectCommand, getSignedUrl } from '@dmwd-io/storage' resolves correctly.
  • @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner are listed as peer dependencies in package.json.
  • S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and S3_ENDPOINT are added to .env.example.
  • Platform usage example (constructing S3Client from env vars) is documented.
  • pnpm typecheck passes.

LLM Handoff Instructions

When implementing this FRD:

  1. Create the packages directory if it does not exist: packages/@dmwd-io/storage/.
  2. Create packages/@dmwd-io/storage/package.json with @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner as peer dependencies (not direct dependencies).
  3. Create packages/@dmwd-io/storage/src/index.ts with export * from '@aws-sdk/client-s3' and export * from '@aws-sdk/s3-request-presigner'.
  4. Add S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and S3_ENDPOINT to .env.example with brief comments.
  5. Add a usage example to the package README or docs showing how to construct S3Client from the platform env vars.
  6. Run pnpm typecheck.

Decision Log

DateDecisionRationale
2026-05-26Single S3-compatible adapter covering AWS S3 and MinIO.The S3 API is the de facto standard. MinIO, R2, and Spaces all implement it. One adapter covers all.
2026-05-26AWS SDK v3 over v2.v3 is modular (tree-shakeable), actively maintained, and the recommended SDK.
2026-05-26Defer multipart upload.Single-part upload handles the current file-size requirements. Multipart adds significant complexity.
2026-06-02Reframed per ADR-014 (Open Source First): adopt @aws-sdk/client-s3 / @aws-sdk/s3-request-presigner as thin re-export rather than building a custom provider interface. Library API is the interface.ADR-014 requires designating the community library as the standard and avoiding custom abstractions that duplicate library capabilities.

Document History

VersionDateAuthorChanges
0.12026-05-26David HolmesInitial draft.
0.22026-06-02David HolmesReframed per ADR-014: ship as thin re-export of @aws-sdk/client-s3 / @aws-sdk/s3-request-presigner, drop custom interface.