All cheat sheets
Storagecheat sheet

S3 Select

Run SQL WHERE clauses inside S3 and receive only the matching rows — pay ~$0.002/GB to scan instead of $0.09/GB to egress whole files. Routinely 40× cheaper when you need a slice of a large CSV, JSON, or Parquet object.

Last reviewed: July 11, 2026

TL;DR: S3 Select runs a SQL SELECT ... WHERE ... inside S3 and streams back only the matching rows. You pay ~$0.002/GB to scan and $0.0007/GB for what's returned — instead of $0.09/GB egress on the whole file plus the compute to filter it. Need 200 MB out of a 10 GB file? ~$0.02 instead of ~$0.90. It also shrinks the Lambda that used to load the whole file into memory.

The numbers

Approach (10 GB file, 200 MB needed) Cost
Download all 10 GB, filter locally ~$0.90
S3 Select: scan 10 GB + return 200 MB ~$0.02

Formats: CSV, JSON (use JSON Lines), and Parquet — Parquet is the double win, since columnar layout means unselected columns aren't even scanned. Field example: an IoT pipeline filtering 2 GB hourly CSVs down to ~20 MB of anomalies cut ~$1,200/month and let the Lambda shrink dramatically.

Do this

  1. Find the "download-then-filter" pattern in your code: Lambdas with big memory settings reading large S3 files, jobs that GetObject gigabytes to extract rows.

  2. Replace the read with SelectObjectContent:

    aws s3api select-object-content --bucket YOUR-BUCKET --key logs/big.csv \
      --expression "SELECT * FROM s3object s WHERE s.status = 'ERROR'" \
      --expression-type SQL \
      --input-serialization '{"CSV":{"FileHeaderInfo":"USE"},"CompressionType":"GZIP"}' \
      --output-serialization '{"JSON":{}}' /dev/stdout
    
  3. Make the WHERE clause selective — the savings are proportional to what you don't return. SELECT * with no filter is paying scan fees for nothing.

  4. Prefer Parquet for new data you'll query this way; JSON Lines over multi-line JSON; standard, boring CSV over clever delimiters.

  5. Cache repeated queries (ElastiCache/DynamoDB) — Select bills per call.

Gotchas

  • The response is an event stream, not a JSON blob — SDKs handle it, but budget 30 minutes of docs-reading the first time.
  • Compression: whole-object GZIP/BZIP2 is fine; anything compressed per-record/chunk inside the file is opaque to Select. Client-side encrypted objects are unqueryable.
  • SQL is a subset: column projection, WHERE, LIKE, CAST, simple aggregates, LIMIT. No JOINs, subqueries, or window functions — one object at a time.
  • Weird CSV breaks it: multi-line fields and exotic delimiters are the classic failure.
  • Scan isn't free: unselective queries on huge files still bill $0.002/GB scanned.

Skip this if

  • Files are tiny — just download them.
  • You need the whole file anyway — no filter, no savings.
  • The question spans many files/partitions with real SQL — that's Athena (the rule of thumb: Select inside your application, Athena at the query console).
  • The data is unstructured (images, video, binaries) or streaming (Kinesis territory). For the same trick on archived data, see Glacier Select.

Run this audit with your AI assistant

Paste this into Claude, ChatGPT, or any agent that can run the AWS CLI with read-only credentials. It audits your account for exactly the waste this sheet describes — and changes nothing.

You are auditing an AWS application for S3 Select opportunities — places
where code downloads large structured objects only to filter them.
Work READ-ONLY; report findings and recommended (unapplied) changes.

1. Identify large structured objects: per major bucket, sample keys by
   extension (.csv, .json, .jsonl, .parquet, .gz) and size (S3 Inventory
   or aws s3api list-objects-v2 --query on sampled prefixes). Flag
   prefixes with many multi-hundred-MB structured files.
2. Identify likely downloaders: Lambda functions and services with
   s3:GetObject on those prefixes (check function env vars/names for
   hints); flag Lambdas with high memory settings (>1 GB) that read
   from those buckets — the classic "load whole file to filter it"
   signature. CloudWatch BytesDownloaded per bucket confirms volume.
3. Cost math per candidate flow: current egress/processing GB × $0.09
   (internet egress; intra-region to Lambda is free but memory/time
   cost still applies) vs Select scan $0.002/GB + $0.0007/GB returned.
   Note the win requires selective WHERE clauses — returning 100% of
   rows saves nothing.
4. Format check: Select needs clean CSV / JSON Lines / Parquet, whole-
   object GZIP at most, no client-side encryption. Flag incompatible
   data.

Report: candidate table (bucket/prefix | file sizes | consumer | est.
current $/mo | est. with Select | blockers), plus one worked
SelectObjectContent example per top candidate. Change nothing.
Works with any assistant that can run shell commands.

Want the guided version?

The S3 Select walkthrough covers this topic interactively — it asks about your setup, branches to what’s relevant, and quizzes you on the tricky parts. Free and anonymous.

Start the walkthrough