S3 clone

S3-compatible object storage — buckets, objects, lifecycle, multipart, and presigned URLs.

S3 clone

Store and retrieve objects in an S3-compatible twin — buckets, multipart uploads, lifecycle expiry on clock advance, presigned URLs, versioning, and object lock — without touching AWS.

Clone ID: s3 · Binary: clones-s3 · SDK kind: s3 · Registry status: shadow (in-memory engine; not a full AWS emulator) · Dashboard: S3 explorer

Start here

QuestionAnswer
Best forInvoice PDFs, report exports, presigned URL flows, lifecycle expiry, and notification webhooks
Connect withAWS SDK v3 with custom endpoint, route mode for s3.amazonaws.com, @molar/clones SDK, or MCP bucket tools
Known limitsIn-memory per run; no cross-region replication
SeedsEmpty by default; seed buckets via JSON or createBucket()

Quick start

import { s3 } from "@molar/clones";

const clone = await s3.start({ seed: "invoice-store", runId: "run-s3-01" });

await clone.createBucket("invoices");
await clone.putObject("invoices", "2026/inv-001.pdf", pdfBytes);
const body = await clone.getObject("invoices", "2026/inv-001.pdf");
const listing = await clone.list("invoices");

await clone.stop();

MCP tools

ToolDescription
molar_clone_spawnSpawn S3 clone (kind: "s3", optional seed)
s3_create_bucketCreate bucket (url, runId, bucket)
s3_putPut object (bucket, key, body)
s3_listListObjectsV2 for a bucket

REST API coverage

S3-compatible API at {endpoint}/t/{runId}/:

OperationSupport
CreateBucket / DeleteBucketYes
PutObject / GetObject / DeleteObjectYes
ListObjectsV2 / list object versionsYes
Multipart upload (initiate, parts, complete, abort)Yes
Bulk delete (?delete)Yes
Range readsYes
Bucket lifecycle rulesYes — expiry on clock advance
Presigned URLsYes — deterministic generation and clock-based expiry
VersioningYes
Object lock (retention / legal hold)Yes
SSE, bucket ACL/policy, object tagsYes
Event notificationsYes — webhook delivery log for PUT, delete, multipart complete

Seeds and initial state

There is no bundled storage-v1 seed. Either create buckets in your test or seed via admin:

await clone.adminPost(`/_clone/seed?runId=${clone.runId}`, {
  buckets: [{ name: "invoices" }],
});

Dashboard preset Invoice PDF lifecycle (stripe + s3 + email) is the fastest way to try a full flow.

Limits

LimitDetail
Destructive-call refusalSDK blocks *.amazonaws.com when credentials look like production keys
LifecycleadvanceClock past expiration days to delete objects
Chaos presetsslow_put, 503_restore, lifecycle_early_delete

AWS SDK configuration

import { S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
  endpoint: clone.endpoint + "/t/" + clone.runId,
  region: "us-east-1",
  credentials: {
    accessKeyId: clone.accessKeyId,
    secretAccessKey: clone.secretAccessKey,
  },
  forcePathStyle: true,
});

Or set:

AWS_ENDPOINT_URL=https://127.0.0.1:<port>/t/<runId>
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-east-1

Lifecycle and virtual clock

await clone.putBucketLifecycle("temp-uploads", { expirationDays: 7 });
await clone.advanceClock("8d");
const objects = await clone.list("temp-uploads");
// objects should be empty

Cross-clone flows

FlowDescription
Stripe invoice PDFStripe finalizes invoice → your app stores PDF in S3
Report exportApp writes CSV; test lists and downloads

Use the Invoice PDF lifecycle preset in the dashboard library.