How to bulk-delete S3 files

TL;DR

Use the DeleteObjects API (plural) — up to 1,000 keys per request. From the AWS CLI: `aws s3 rm --recursive` against a prefix. From a tool: multi-select in S3 Viewer and bulk-delete in one round trip. If versioning is on, each delete only adds a delete marker — you'll need to delete every version explicitly to actually purge.

Steps

Step-by-step.

  1. 01

    In S3 Viewer: shift-click a range, then Delete

    Multi-select keys in the file browser (shift-click for ranges, cmd-click for individual). Right-click → Delete or press the toolbar button. S3 Viewer batches the selection into a single DeleteObjects call — up to 1,000 keys per request, the way the API was designed.
  2. 02

    AWS CLI: delete a whole prefix

    The CLI lists every key under the prefix and deletes them in batches of 1,000 under the hood.
    aws s3 rm s3://my-bucket/old-logs/ --recursive
  3. 03

    AWS CLI: delete from a key list

    For non-contiguous keys, build a JSON delete request and pass it to aws s3api delete-objects.
    aws s3api delete-objects \
      --bucket my-bucket \
      --delete '{"Objects":[{"Key":"a.log"},{"Key":"b.log"}]}'
  4. 04

    AWS SDK: DeleteObjectsCommand

    For programmatic bulk delete, use DeleteObjectsCommand in batches of up to 1,000. The response includes any per-key errors, so you can retry failures without re-running the whole batch.
    const result = await s3.send(
      new DeleteObjectsCommand({
        Bucket: 'my-bucket',
        Delete: {
          Objects: keys.map((Key) => ({ Key })),
          Quiet: false,
        },
      }),
    );
  5. 05

    If versioning is on: also delete the versions

    On a versioned bucket, a normal delete just adds a delete marker. To actually purge, list every version and delete each one explicitly with its VersionId. S3 Viewer prompts you when versioning is on so you know you're doing a soft delete vs. a hard one.
    aws s3api list-object-versions \
      --bucket my-bucket --prefix old-logs/ \
      --query 'Versions[].{Key:Key,VersionId:VersionId}' \
      > versions.json
  6. 06

    Lifecycle rules for ongoing cleanup

    For predictable cleanup (e.g., delete logs older than 30 days), use S3 Lifecycle rules instead of running deletes yourself. Cheap, automatic, and survives you forgetting.
Under the hood

What's actually happening.

S3's DeleteObjects API takes up to 1,000 keys per request and returns a per-key result list — successes and failures together. For larger deletes you batch by 1,000 and reissue any failed keys. The AWS CLI's rm --recursive handles the listing and batching for you under the hood. S3 Viewer wraps the same API in a multi-select UI: shift-click a range, hit Delete, one round trip. On versioned buckets, every “delete” is really a soft delete (it writes a delete marker); to actually purge, you have to enumerate versions and delete each one with its VersionId. For predictable cleanup, lifecycle rules are the right long-term tool.

FAQ

Common questions.

How do I bulk-delete files from S3?

Use the DeleteObjects API (plural) — up to 1,000 keys per request. The simplest invocations: `aws s3 rm s3://bucket/prefix --recursive` from the CLI, or multi-select in S3 Viewer and click Delete. For programmatic deletes, use the SDK's DeleteObjectsCommand in batches of 1,000. The AWS S3 console handles single-key delete; for many keys at once, use the CLI, an SDK, or a tool like S3 Viewer that wraps the bulk API.

How many objects can I delete in one S3 API call?

Up to 1,000 per DeleteObjects request. For more, batch them — most SDKs and tools handle the batching for you. S3 Viewer batches automatically; the AWS CLI's `rm --recursive` does too.

How do I delete all files in an S3 bucket prefix?

From the CLI: `aws s3 rm s3://bucket/prefix/ --recursive` lists every key under the prefix and deletes them in 1,000-key batches. From S3 Viewer: select the prefix in the sidebar and use bulk delete. Programmatically: list with ListObjectsV2 and call DeleteObjects.

Why didn't my bulk delete remove my files?

Almost always versioning. On a versioned bucket, DeleteObjects writes a delete marker per key — the prior versions are still there (and still billed). Use ListObjectVersions to enumerate every version and DeleteObject with --version-id to fully purge.

Can I undo a bulk delete in S3?

Only if versioning was enabled when you deleted. Remove the delete markers (or restore the prior versions) to bring objects back. Without versioning, bulk deletes are permanent — there is no recycle bin.

Does Cloudflare R2 support bulk delete?

Yes. R2 implements DeleteObjects the same way as AWS S3 — up to 1,000 keys per request. The same CLI commands work with `--endpoint-url` set to R2; S3 Viewer's bulk-delete UI works against R2 buckets identically.
Use S3 Viewer for this

Skip the CLI. Try it in the browser.

S3 Viewer turns the steps above into a single click. Open source, self-hostable, free for personal use.