What Is Amazon S3 Tables? Pricing With Examples, Apache Iceberg Explained, Setup, Compaction and S3 Tables vs a Normal Bucket

Logeshwaran
—

Amazon S3 Tables is S3 storage built for analytics tables. Instead of a normal bucket full of files, you create a table bucket, and each table in it is an Apache Iceberg table that S3 manages for you: it compacts small files, expires old snapshots and deletes files nothing points to, automatically. You query your tables with Amazon Athena, Redshift, EMR, Glue, Apache Spark, DuckDB or PyIceberg, and you can update and delete rows, change the schema and time-travel to earlier versions, which plain files in S3 cannot do on their own. In US East you pay $0.0265 per GB-month for storage (about 15% more than S3 Standard's $0.023), $0.025 per 1,000 objects a month for monitoring, normal-looking request fees ($0.005 per 1,000 writes, $0.0004 per 1,000 reads), and for compaction $0.002 per 1,000 objects plus $0.005 per GB processed ($0.01 per GB for sort and z-order). A 50 GB table costs you about $2 a month, and 1 TB of streaming data with heavy compaction about $36. Below: what S3 Tables and Iceberg are, how they work, every price with worked examples, setup in the console, CLI, Athena, Spark and PyIceberg, the automatic maintenance and its settings, S3 Tables vs Iceberg in a normal bucket, quotas, and fixes for the errors you are most likely to hit.

Jake's repair shop had been running a small data lake for a while: nightly CSV exports in S3, queried with Athena. It worked well until Jake asked for something simple. Repair tickets change status (received, diagnosing, waiting for parts, ready, collected), and he wanted a table that always showed each ticket's current status. With plain files in S3, every status change meant either rewriting a whole file or stacking up new rows and working out the latest one in every query. "Can't the table just update the row like a spreadsheet does?" Jake asked. Ethan opened the S3 console and pointed at a menu item called Table buckets.

⚡ Quick Answer

• What it is: table buckets that store Apache Iceberg tables and maintain them for you, queried by Athena, Spark and more. Explained.

• Price: $0.0265/GB-month storage, $0.025 per 1,000 objects monitoring, compaction $0.002 per 1,000 objects + $0.005/GB. Every rate.

• Why: row updates and deletes, schema changes and time travel, without running compaction yourself. Iceberg in plain English.

• Start: create a table bucket with integration on, a namespace, then a table from Athena or the CLI. Setup.

How it works · Worked costs · Spark and PyIceberg · Maintenance · vs Iceberg in a bucket · Errors · FAQ.

New to data on S3? The cards below cover Athena, S3 itself, Lake Formation, and S3 request and storage pricing, which you will want next to S3 Tables.

🧭 NEW HERE? READ THESE FIRST

These five pages explain the S3 and analytics pieces S3 Tables builds on:

📌 Bookmark this; the price table, the worked costs and the maintenance settings are the parts you will come back for.

What is Amazon S3 Tables?

Amazon S3 Tables, launched at the end of 2024, is a kind of S3 storage made for tabular data: orders, transactions, sensor readings, logs, repair tickets, anything with rows and columns that you analyze. It adds three new things to S3:

  • Table buckets: a new bucket type, next to the general purpose buckets you know (and directory and vector buckets). A table bucket holds tables, not loose files.
  • Namespaces: groups of tables inside a table bucket, like databases or schemas. Your query engine shows a namespace as a database.
  • Tables: each one an Apache Iceberg table, with its own data files (Parquet by default), metadata files, snapshots and permissions. Each table has its own ARN, so you can grant access table by table.

On top of storage, S3 does the housekeeping that Iceberg tables need and that you would otherwise script yourself: compaction (merging many small files into fewer large ones), snapshot management (expiring old versions) and unreferenced file removal (deleting files no snapshot uses). All three are on by default.

Your tables are reachable from the AWS analytics services through an integration with the AWS Glue Data Catalog (a catalog named s3tablescatalog), and from open source engines through an Iceberg REST endpoint. S3 itself uses table buckets for features such as S3 Metadata, which keeps a queryable table of every object in a general purpose bucket.

What you would use S3 Tables for: analytics tables that change (status updates, corrections, late-arriving data, GDPR deletes), streaming data that lands as many small files, a lakehouse that several engines share, and any Iceberg table you would rather not maintain by hand.

Jake: "So it's a bucket that knows it's holding spreadsheets, not just files."

Ethan: "And it tidies them up every night without anyone asking."

Apache Iceberg in plain English

If you have queried CSV or Parquet files in S3, you have seen the limits of plain files. A query engine reading a folder of files cannot easily update one row, delete one customer, rename a column or show you yesterday's version, and two writers at once can corrupt a result. Apache Iceberg is an open table format that fixes that by adding a layer of metadata files on top of your data files:

  • Snapshots: every write creates a new snapshot listing exactly which data files make up the table at that moment. Readers always see one consistent snapshot, so you get ACID transactions on S3.
  • Row-level updates and deletes: UPDATE, DELETE and MERGE INTO work, either by rewriting the affected files or by writing small delete files that later compaction folds in.
  • Schema evolution: add, drop, rename or reorder columns without rewriting your data.
  • Hidden partitioning: partition by day or month of a timestamp, and your queries benefit without you adding partition columns to every WHERE clause.
  • Time travel: query the table as it was at an earlier snapshot or time, and roll back a bad write.
  • Open format: Spark, Trino, Flink, Athena, Redshift, Snowflake, DuckDB and others read and write the same tables.

Data types in your tables are Iceberg types: boolean, int, long, float, double, decimal(p,s), date, time, timestamp (without time zone) and timestamptz (with time zone), string, uuid, fixed and binary, plus nested struct, list and map. Your query engine maps its own types onto these; in Athena, for example, you write bigint for long and timestamp for timestamp.

The cost of those features is housekeeping. Every small write adds files, metadata grows with every snapshot, and old files pile up. If you run Iceberg in a general purpose bucket, you schedule compaction, snapshot expiry and orphan file cleanup yourself. S3 Tables does that part for you, which is most of what you pay for.

How S3 Tables work, step by step

Here is what happens between creating a table bucket and running your first query:

  1. You create a table bucket in a Region, with the AWS analytics integration turned on, which links table buckets in that Region to the Glue Data Catalog as s3tablescatalog.
  2. You create a namespace in the bucket, for example repairs.
  3. You create a table with a schema, from Athena SQL, the CLI, Spark or PyIceberg. S3 stores the table's first metadata file.
  4. Your engine writes data. It writes Parquet data files into the table's storage, then commits a new snapshot by updating the table's metadata pointer through the S3 Tables API. Readers see the new data only after that commit succeeds.
  5. Your updates and deletes add new data files or delete files and another snapshot.
  6. Maintenance runs in the background. Compaction merges small files toward the target size (512 MB by default), snapshot management expires snapshots older than the maximum age (120 hours by default) while keeping at least the minimum (1), and unreferenced file removal deletes files nothing uses after the days you set.
  7. You query from Athena, Redshift, EMR, Glue or any Iceberg engine, which reads the current snapshot's metadata and only the files that snapshot lists.

Amazon S3 Tables pricing

Your S3 Tables bill has five parts. US East (N. Virginia) prices in October 2026:

What you pay forPrice
Storage, standard (first 50 TB / next 450 TB / over 500 TB)$0.0265 / $0.0253 / $0.0242 per GB-month
Storage, Intelligent-Tiering: Frequent AccessSame as standard, from $0.0265 per GB-month
Storage, Intelligent-Tiering: Infrequent Access$0.0144 per GB-month
Storage, Intelligent-Tiering: Archive Instant Access$0.0046 per GB-month
Object monitoring$0.025 per 1,000 objects per month
PUT, COPY, POST and LIST requests$0.005 per 1,000
GET and all other requests$0.0004 per 1,000
Compaction, binpack (default for unsorted tables)$0.002 per 1,000 objects + $0.005 per GB processed
Compaction, sort or z-order$0.002 per 1,000 objects + $0.01 per GB processed
Replication$0.01 per 1,000 table updates + $0.005 per 1,000 replicated PUTs + data transfer (for example $0.02 per GB between US Regions) + destination storage

How this compares with a general purpose bucket: S3 Standard storage is $0.023 per GB-month, so S3 Tables storage costs about 15% more, and S3 Standard has no per-object monitoring fee and no compaction charge. In return, you get the maintenance and the managed table catalog. Requests are priced like S3 Standard requests, which our S3 request pricing guide explains in detail.

The monitoring fee counts every object in your tables, data files and metadata files alike, which is why compaction matters: a table of 2 million tiny files costs $50 a month in monitoring alone, and the same data compacted into 2,000 files of 512 MB costs 5 cents.

Your query engine bills separately: Athena at $5 per TB scanned, Glue and EMR for their compute, Redshift for its warehouse.

Worked examples: what S3 Tables really cost

Example 1: Jake's repair tickets table. 50 GB of data, about 5,000 objects (data files plus metadata) after compaction, 1,000 writes a day and 300,000 reads a month.

  • Storage: 50 x $0.0265 = $1.33
  • Monitoring: 5,000 / 1,000 x $0.025 = $0.13
  • Writes: 30,000 / 1,000 x $0.005 = $0.15
  • Reads: 300,000 / 1,000 x $0.0004 = $0.12
  • Compaction: 30,000 objects x $0.002 / 1,000 = $0.06, plus 30 GB processed x $0.005 = $0.15
  • Total: about $1.94 a month, compared with $1.15 for the same 50 GB as plain files in S3 Standard, which could not update a row.

Example 2: 1 TB of streaming events. Amazon Data Firehose writes into a table every minute, about 10 small files per commit, so about 432,000 new objects a month. After compaction the table holds about 10,000 objects. Reads: 2 million a month.

  • Storage: 1,024 GB x $0.0265 = $27.14
  • Monitoring: 10,000 / 1,000 x $0.025 = $0.25
  • Writes: 432,000 / 1,000 x $0.005 = $2.16
  • Reads: 2,000,000 / 1,000 x $0.0004 = $0.80
  • Compaction: 432,000 objects x $0.002 / 1,000 = $0.86, plus 1,024 GB processed x $0.005 = $5.12
  • Total: about $36.33 a month. Without compaction your monitoring fee would climb past $10 a month by the end of the first month and keep growing, and your queries would slow down as they opened hundreds of thousands of files.

Example 3: 100 TB of history with Intelligent-Tiering. 10% of the data is read often, 70% rarely and 20% almost never.

  • Frequent Access: 10,240 GB x $0.0265 = $271.36
  • Infrequent Access: 71,680 GB x $0.0144 = $1,032.19
  • Archive Instant Access: 20,480 GB x $0.0046 = $94.21
  • Storage total: $1,397.76 a month, compared with $2,652.16 for 100 TB in the standard tier (51,200 GB x $0.0265 + 51,200 GB x $0.0253), a saving of about $1,254 a month.

Example 4: sort compaction. If your queries always filter by customer and date, a sort order with sort compaction makes them read far less data. For 500 GB of new data a month, compaction bytes cost 500 x $0.01 = $5.00 instead of $2.50 with binpack; the extra $2.50 usually pays for itself in Athena scan savings within a few queries.

Example 5: S3 Tables vs doing it yourself. The same 1 TB as Example 2, as an Iceberg table in a general purpose bucket: storage 1,024 x $0.023 = $23.55, similar request costs ($2.96), and your own maintenance, for example a managed Glue compaction job using 2 DPUs for 30 minutes a day, 30 DPU-hours x $0.44 = $13.20, plus snapshot-expiry and cleanup jobs you write and schedule. That is about $39.71 a month plus your time, against about $36.33 for S3 Tables with nothing to schedule. For most teams the managed table is the cheaper option once you count the maintenance.

Ethan: "About two dollars a month for the tickets table, and you get to type UPDATE like it's a normal database."

Jake: "Two dollars. I spend more than that on coffee for the guy who updates the spreadsheet."

S3 Tables cost and features vs a normal S3 bucket

If you are deciding between a table bucket and the general purpose bucket you already use, this is the comparison you need:

 S3 Tables (table bucket)General purpose bucket
Storage, first 50 TB$0.0265 per GB-month$0.023 per GB-month (S3 Standard)
Per-object fee$0.025 per 1,000 objects a monthNone (Intelligent-Tiering has its own small fee)
Requests$0.005 per 1,000 writes, $0.0004 per 1,000 readsSame
Compaction and cleanupAutomatic, billed per object and GBYou build and pay for it yourself
What it storesApache Iceberg tables onlyAny object: files, images, backups, any table format
Row updates, deletes, time travelBuilt in (Iceberg)Only if you add Iceberg, Delta Lake or Hudi yourself
CatalogBuilt-in table catalog, plus Glue integration and REST endpointYou choose and run one (usually the Glue Data Catalog)
Permissionss3tables: actions, per table bucket and per tables3: actions, per bucket and prefix
Best forAnalytics tables that change, streaming, shared lakehouse tablesEverything else, and append-only files you query as-is

A useful way to think about it: if your data is a table that people query and correct, a table bucket is worth its 15% storage premium. If it is files that people download, archive or process one at a time, keep it in a general purpose bucket, with the storage class chosen as in our S3 storage classes guide.

Set up S3 Tables: console, CLI and Athena

The fastest way to your first table, in the console:

  1. Open the S3 console, choose Table buckets, then Create table bucket.
  2. Name it (3 to 63 characters, lowercase letters, numbers and hyphens), for example jakes-repairs-tables, and keep Enable integration with AWS analytics services checked. This connects your table buckets to the Glue Data Catalog as s3tablescatalog.
  3. Choose encryption: SSE-S3 (the default) or SSE-KMS with your own key. For KMS, see the errors section for the key policy the maintenance service needs.
  4. Open the bucket and choose Create table with Athena, or create a namespace first.
  5. In Athena, pick the data source AwsDataCatalog, the catalog s3tablescatalog/jakes-repairs-tables, create the namespace as a database, and create the table with SQL (below).
  6. Insert, update and query rows from Athena, or connect Spark or another engine.

Use all-lowercase names for namespaces, tables and columns. The Glue Data Catalog integration expects lowercase, and a table created with capital letters in its name can be invisible to Athena. Our Athena guide covers querying S3 Tables alongside ordinary files.

The same with the AWS CLI:

# Create a table bucket and a namespace
aws s3tables create-table-bucket --name jakes-repairs-tables --region us-east-1
aws s3tables create-namespace \
  --table-bucket-arn arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables \
  --namespace repairs

# Create an Iceberg table with a schema
aws s3tables create-table \
  --table-bucket-arn arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables \
  --namespace repairs --name tickets --format ICEBERG \
  --metadata '{"iceberg":{"schema":{"fields":[
     {"name":"ticket_id","type":"long","required":true},
     {"name":"status","type":"string"},
     {"name":"updated_at","type":"timestamp"}]}}}'

# List what you have
aws s3tables list-tables \
  --table-bucket-arn arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables

And in Athena, with s3tablescatalog/jakes-repairs-tables selected as the catalog:

CREATE DATABASE IF NOT EXISTS repairs;

CREATE TABLE repairs.tickets (
  ticket_id  bigint,
  customer   string,
  status     string,
  updated_at timestamp)
PARTITIONED BY (day(updated_at))
TBLPROPERTIES ('table_type' = 'iceberg');

INSERT INTO repairs.tickets VALUES (1042, 'maria', 'received', current_timestamp);

-- The part plain files cannot do: change one row in place
UPDATE repairs.tickets SET status = 'ready', updated_at = current_timestamp
WHERE ticket_id = 1042;

SELECT ticket_id, status FROM repairs.tickets WHERE status = 'ready';

Use S3 Tables from Spark, EMR, Glue, Firehose, PyIceberg and DuckDB

  • Amazon Athena and Amazon Redshift: through the Glue Data Catalog integration; your table bucket appears as a catalog and each namespace as a database. Athena supports SELECT, INSERT, UPDATE, DELETE and MERGE on these tables. Redshift can query them alongside its own tables.
  • Apache Spark on EMR, Glue or your own cluster: either through the Glue Data Catalog, or directly with the Amazon S3 Tables Catalog for Apache Iceberg client library. Your Spark settings look like this:
spark.sql.catalog.s3tablesbucket=org.apache.iceberg.spark.SparkCatalog
spark.sql.catalog.s3tablesbucket.catalog-impl=software.amazon.s3tables.iceberg.S3TablesCatalog
spark.sql.catalog.s3tablesbucket.warehouse=arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables
spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions

-- then in Spark SQL
MERGE INTO s3tablesbucket.repairs.tickets t
USING updates u ON t.ticket_id = u.ticket_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
  • Amazon Data Firehose: streams records straight into an S3 table, which is the easiest way for you to land clickstreams, IoT readings or logs; compaction then takes care of the small files.
  • PyIceberg and DuckDB: through the Iceberg REST endpoint, https://s3tables.REGION.amazonaws.com/iceberg, signed with your AWS credentials. For governance across many buckets, point them at the AWS Glue Iceberg REST endpoint instead. A PyIceberg example:
from pyiceberg.catalog import load_catalog

catalog = load_catalog("s3tables", **{
    "type": "rest",
    "uri": "https://s3tables.us-east-1.amazonaws.com/iceberg",
    "warehouse": "arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables",
    "rest.sigv4-enabled": "true",
    "rest.signing-name": "s3tables",
    "rest.signing-region": "us-east-1",
})
tickets = catalog.load_table("repairs.tickets")
print(tickets.scan(row_filter="status == 'ready'").to_pandas())
  • Snowflake: since August 2026, Snowflake connects directly to the S3 Tables Iceberg REST endpoint with a catalog integration (catalog API type AWS_S3TABLES, your table bucket ARN as the catalog name, and vended credentials) and a catalog-linked database, so your Snowflake users can query and write your tables without copying data. CREATE TABLE AS SELECT is not supported on that route. If you need Lake Formation's fine-grained permissions, connect Snowflake through the AWS Glue Iceberg REST endpoint instead.
  • Trino, ClickHouse and other Iceberg REST clients: engines that speak the Iceberg REST catalog protocol connect the same way PyIceberg does, with SigV4 signing for the s3tables service, or through the Glue endpoint.
  • Amazon QuickSight and Tableau: connect through Athena. Build a dataset on the Athena table in s3tablescatalog, and your dashboards read the current snapshot every time they refresh.
  • Logs: Amazon CloudWatch Logs can publish log data into S3 Tables, which lets you query months of logs with SQL at S3 prices instead of keeping them in CloudWatch.

One rule applies to every engine: write your data through an Iceberg-aware engine or the table APIs, not by copying files into the table's storage. A file that no snapshot references is invisible to queries, and unreferenced file removal deletes it after a few days.

The S3 Tables API and Python (boto3)

S3 Tables has its own API, separate from the S3 object API, and the AWS CLI command group is aws s3tables. The operations you will use most:

  • Table buckets: CreateTableBucket, ListTableBuckets, GetTableBucket, DeleteTableBucket, PutTableBucketPolicy, PutTableBucketEncryption and PutTableBucketMaintenanceConfiguration (for unreferenced file removal).
  • Namespaces: CreateNamespace, ListNamespaces, GetNamespace, DeleteNamespace.
  • Tables: CreateTable, ListTables, GetTable, RenameTable, DeleteTable, PutTablePolicy, and GetTableMetadataLocation and UpdateTableMetadataLocation, which engines use to read and commit the pointer to a table's current metadata file.
  • Maintenance: GetTableMaintenanceConfiguration, PutTableMaintenanceConfiguration and GetTableMaintenanceJobStatus.

These manage your tables; they do not read or write rows. For rows you use a query engine or an Iceberg library such as PyIceberg. Here is a boto3 script that sets up a bucket, a namespace and a table and checks maintenance, the kind of thing you would put in a deployment pipeline:

import boto3

s3t = boto3.client("s3tables", region_name="us-east-1")

bucket_arn = s3t.create_table_bucket(name="jakes-repairs-tables")["arn"]
s3t.create_namespace(tableBucketARN=bucket_arn, namespace=["repairs"])

s3t.create_table(
    tableBucketARN=bucket_arn, namespace="repairs", name="tickets", format="ICEBERG",
    metadata={"iceberg": {"schema": {"fields": [
        {"name": "ticket_id", "type": "long", "required": True},
        {"name": "status", "type": "string"},
        {"name": "updated_at", "type": "timestamp"},
    ]}}},
)

for t in s3t.list_tables(tableBucketARN=bucket_arn, namespace="repairs")["tables"]:
    print(t["name"], t["arn"])

status = s3t.get_table_maintenance_job_status(
    tableBucketARN=bucket_arn, namespace="repairs", name="tickets")
print(status["status"])   # per job: compaction, snapshot management, file removal

In Terraform and CloudFormation the resources are aws_s3tables_table_bucket, aws_s3tables_namespace and aws_s3tables_table, and AWS::S3Tables::TableBucket, AWS::S3Tables::Namespace and AWS::S3Tables::Table, so you can keep your table definitions in code next to the rest of your infrastructure.

Automatic maintenance: compaction, snapshots and cleanup

All three maintenance jobs are on by default, and you can change or turn off each one:

  • Compaction (per table): merges small files toward a target file size of 512 MB by default, or any size you set from 64 MB to 512 MB, and folds row-level deletes into the data. Strategies: auto (default; sort if your table has a sort order, otherwise binpack), binpack, sort and z-order (both need a sort order in your table properties, and cost more). Works on Parquet, Avro and ORC files.
  • Snapshot management (per table): keeps at least MinimumSnapshots (1 by default) and expires snapshots older than MaximumSnapshotAge (120 hours, five days, by default). Files used only by expired snapshots become noncurrent. Your time travel window is therefore about five days unless you raise the age.
  • Unreferenced file removal (per table bucket): marks files that no snapshot references as noncurrent after 3 days (unreferencedDays), and deletes noncurrent files after 10 days (nonCurrentDays). These deletes are permanent; recovering a noncurrent file needs AWS Support before it is deleted.

Change them with the CLI:

# Smaller target files (256 MB) for a table read by many small queries
aws s3tables put-table-maintenance-configuration \
  --table-bucket-arn arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables \
  --namespace repairs --name tickets --type icebergCompaction \
  --value '{"status":"enabled","settings":{"icebergCompaction":{"targetFileSizeMB":256}}}'

# Keep 30 days of history for time travel (720 hours), at least 10 snapshots
aws s3tables put-table-maintenance-configuration \
  --table-bucket-arn arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables \
  --namespace repairs --name tickets --type icebergSnapshotManagement \
  --value '{"status":"enabled","settings":{"icebergSnapshotManagement":{"minSnapshotsToKeep":10,"maxSnapshotAgeHours":720}}}'

# Check whether the last maintenance jobs succeeded
aws s3tables get-table-maintenance-job-status \
  --table-bucket-arn arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables \
  --namespace repairs --name tickets

Longer history costs you more storage, because the files that older snapshots need stay around. Raise the age only as far as you really need for audits or rollbacks.

Time travel and rolling back a bad write

Because every write creates a snapshot, you can look at your table as it was at an earlier point, as long as that snapshot has not expired (five days by default). In Athena:

-- The board as it looked last Tuesday morning
SELECT ticket_id, status
FROM repairs.tickets FOR TIMESTAMP AS OF TIMESTAMP '2026-10-13 09:00:00 UTC';

-- Or by snapshot ID, from the table's history
SELECT * FROM "repairs"."tickets$history";
SELECT * FROM repairs.tickets FOR VERSION AS OF 4893016628551337745;

Iceberg also gives you metadata tables you can query like any other table: $history lists every snapshot with its time and parent, $snapshots shows what each write did (rows and files added or removed), $files lists the data files in the current snapshot with their sizes, and $partitions summarizes each partition. They are how you answer questions such as "which job wrote those bad rows at 3 a.m.?", "how many small files is compaction still working through?" and "how big is each day's partition?", without opening the S3 console at all. You can also reproduce last month's report exactly, by running the report's query against the snapshot that existed when it was first produced.

To undo a bad write, find the last good snapshot in the history and roll the table back to it with your Spark engine's Iceberg procedure (for example CALL s3tablesbucket.system.rollback_to_snapshot('repairs.tickets', 4893016628551337745)), or copy the old rows back with an INSERT from the time-travel query. Time travel only reaches as far back as your snapshot retention, so if you need to audit last month, raise maxSnapshotAgeHours before you need it, not after.

Security and access

  • IAM actions use their own prefix, s3tables: (for example s3tables:GetTableData, s3tables:PutTableData, s3tables:CreateTable), and resources are table bucket and table ARNs (arn:aws:s3tables:REGION:ACCOUNT:bucket/NAME/table/ID). Your existing s3: policies do not cover table buckets.
  • Resource policies can be attached to a table bucket or to a single table, for cross-account sharing.
  • Fine-grained access (column, row and cell level) comes from AWS Lake Formation when your engines read through the Glue Data Catalog.
  • Encryption: SSE-S3 by default, or SSE-KMS with a key you control, set per bucket or per table. Our KMS guide covers keys and key policies.
  • Logging: table operations and automated maintenance jobs show up in AWS CloudTrail.

S3 Tables permissions, by role. Most access problems come from giving a role S3 permissions instead of S3 Tables permissions, or from forgetting the data actions. A role that only reads tables needs s3tables:GetTableBucket, s3tables:GetNamespace, s3tables:GetTable, s3tables:GetTableMetadataLocation and s3tables:GetTableData. A role that writes also needs s3tables:PutTableData and s3tables:UpdateTableMetadataLocation (the commit). An admin role adds the Create, Delete, Rename and Put...Policy and maintenance actions. A reader policy for your bucket looks like this:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "s3tables:GetTableBucket", "s3tables:GetNamespace", "s3tables:GetTable",
      "s3tables:GetTableMetadataLocation", "s3tables:GetTableData"
    ],
    "Resource": [
      "arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables",
      "arn:aws:s3tables:us-east-1:111122223333:bucket/jakes-repairs-tables/table/*"
    ]
  }]
}

If your engines read through the Glue Data Catalog with Lake Formation turned on, Lake Formation grants decide what each user sees, and your role also needs lakeformation:GetDataAccess. For an SSE-KMS bucket, add kms:Decrypt (and kms:GenerateDataKey for writers) on the key.

S3 Tables vs Iceberg in a general purpose bucket, Redshift and Delta Lake

  • S3 Tables vs your own Iceberg tables in a general purpose bucket: same open format and engines. In a general purpose bucket you pay $0.023 per GB, but you schedule compaction, snapshot expiry and orphan cleanup yourself and choose your own catalog. S3 Tables costs a little more per GB, adds monitoring and compaction fees, and does all the maintenance. Choose your own bucket when you need full control of every Iceberg setting or already run maintenance well; choose S3 Tables when you would rather not.
  • S3 Tables vs plain Parquet in S3: plain Parquet is cheapest and fine for append-only data you never correct. As soon as you need updates, deletes, schema changes or safe concurrent writes, a table format pays off.
  • S3 Tables vs Amazon Redshift: Redshift is a data warehouse with its own compute and storage, best for heavy, concurrent SQL and dashboards. S3 Tables is open storage that many engines, Redshift included, can use. Many teams keep curated history in S3 Tables and hot reporting data in Redshift.
  • S3 Tables vs Delta Lake or Databricks: Delta Lake is a different open table format, centered on Databricks. S3 Tables is Iceberg-only. If your company standardizes on Iceberg across AWS, Snowflake and open source engines, S3 Tables fits; if it standardizes on Databricks, Delta tables in general purpose buckets (or Databricks-managed storage) usually fit better.
  • S3 Tables vs PostgreSQL: PostgreSQL is a transactional database for your application: thousands of small reads and writes a second, indexes, constraints, millisecond lookups. S3 Tables is analytics storage: large scans over millions or billions of rows, cheap at scale, with no server. A common pattern is to keep your app's live data in PostgreSQL (or Amazon RDS) and copy it into S3 Tables every hour or night for reporting.
  • S3 table vs Glue table: a Glue Data Catalog table is only metadata pointing at files somewhere in S3; an S3 table is the storage, the Iceberg metadata and the maintenance together. When you enable the integration, each S3 table also appears as a table in the Glue Data Catalog's s3tablescatalog, so you get both views of the same data.
  • S3 Tables vs S3 Vectors: different jobs. S3 Vectors stores embeddings for AI similarity search; S3 Tables stores rows and columns for analytics.

Quotas, names and Regions

  • Table buckets: 100 per Region per account by default (increase through AWS Support).
  • Namespaces: 10,000 per table bucket. Tables: 10,000 per table bucket.
  • Bucket names: 3 to 63 characters, lowercase letters, numbers and hyphens, unique in your account and Region; our InvalidBucketName guide lists the naming rules for every S3 bucket type.
  • Namespace, table and column names: lowercase for the AWS analytics integration.
  • Endpoints: s3tables.REGION.amazonaws.com, plus dual-stack (IPv6) endpoints and AWS PrivateLink for private access from your VPC.
  • Regions: S3 Tables is available in most commercial Regions and, since February 2026, in AWS GovCloud (US-East) and AWS GovCloud (US-West). Replication is not available in the GovCloud Regions. Check the S3 endpoints list for your Region before you plan a deployment.

Two practical notes on these limits. First, 10,000 tables per bucket is plenty for most teams, but if you create a table per customer or per device, you can reach it; use one table with a customer or device column instead, partitioned or sorted on it. Second, each table bucket is a separate unit for encryption, maintenance settings and policies, so it is often easier for you to use one bucket per environment (production, test) or per team than one giant bucket for everything.

Common S3 Tables errors and fixes

  • The table does not appear in Athena: the integration was not enabled when the bucket was created (enable it from the table bucket's page), you are looking in AwsDataCatalog instead of s3tablescatalog/your-bucket, or the table or namespace name has uppercase letters.
  • AccessDenied with a policy that allows s3:*: table buckets use s3tables: actions. Add the s3tables permissions (and Lake Formation grants, if Lake Formation governs the catalog) to the role your engine uses.
  • CreateTable fails on an SSE-KMS bucket: the S3 Tables maintenance service principal, maintenance.s3tables.amazonaws.com, needs kms:GenerateDataKey and kms:Decrypt on your key, scoped with a kms:EncryptionContext:aws:s3:arn condition to your table bucket. S3 checks this on every table creation. Your engine's IAM role needs the same key permissions to read and write.
  • Snapshot management shows FAILED: the table has a user-defined Iceberg tag or branch, or the Iceberg properties history.expire.max-snapshot-age-ms or history.expire.min-snapshots-to-keep are set. Remove them (for example ALTER TABLE repairs.tickets UNSET TBLPROPERTIES ('history.expire.max-snapshot-age-ms')) and configure retention with the S3 Tables maintenance settings instead.
  • Sort or z-order compaction will not turn on: your table has no sort order in its Iceberg properties, or the caller lacks s3tables:GetTableData.
  • Files you copied into the table disappeared: they were never committed to a snapshot, so unreferenced file removal deleted them. Load data with an engine (INSERT, Spark, Firehose, PyIceberg).
  • Commit conflicts with two writers: Iceberg uses optimistic concurrency, so one of two simultaneous commits on the same data retries or fails. Let your engine retry, or schedule writers so they touch different partitions.
  • Queries got slow after a burst of small writes: compaction runs in the background and needs time to catch up. Check the maintenance job status; if compaction is disabled, turn it back on.

Best practices

  • Keep compaction on and leave the 512 MB target unless your queries are tiny and frequent.
  • Partition by time with Iceberg's hidden partitioning (day(updated_at)) and add a sort order on the column your users filter by most.
  • Batch your writes where you can: fewer, larger commits mean fewer objects, lower request and compaction fees and faster queries.
  • Use Intelligent-Tiering for large history that cools down over time.
  • Set snapshot retention deliberately: five days is fine for most tables; audit tables may need weeks.
  • Use lowercase names everywhere and one namespace per subject area.
  • Grant s3tables permissions per table and use Lake Formation for column-level access.
  • Watch the bill's components: monitoring and compaction lines that grow faster than storage usually mean too many small writes.

Frequently asked questions

What is Amazon S3 Tables?

S3 storage built for analytics tables. You create a table bucket, and each table in it is an Apache Iceberg table that S3 maintains automatically with compaction, snapshot expiry and cleanup. You query it with Athena, Redshift, EMR, Glue, Spark or any Iceberg engine.

What is a table bucket in S3?

A bucket type that holds tables instead of loose objects. Inside it you create namespaces (like databases) and tables (Iceberg tables), each with its own ARN and permissions, using s3tables API actions.

How much does S3 Tables cost?

In US East, storage is $0.0265 per GB-month for the first 50 TB, monitoring $0.025 per 1,000 objects a month, writes $0.005 per 1,000, reads $0.0004 per 1,000, and compaction $0.002 per 1,000 objects plus $0.005 per GB processed ($0.01 per GB for sort or z-order).

Is S3 Tables more expensive than S3 Standard?

Per GB, a little: $0.0265 vs $0.023, plus monitoring and compaction fees. Once you count the compute and engineering for running Iceberg maintenance yourself, S3 Tables usually costs about the same or less.

What is Apache Iceberg?

An open table format that adds metadata and snapshots on top of data files in object storage, giving you ACID transactions, row-level updates and deletes, schema evolution, hidden partitioning and time travel. Most analytics engines support it.

Can I update and delete rows in S3 Tables?

Yes. Use UPDATE, DELETE and MERGE INTO from Athena, Spark or other Iceberg engines. Each change creates a new snapshot, and compaction later folds delete files into the data.

How do I query S3 Tables with Athena?

Create the table bucket with the analytics integration enabled, use lowercase names, then in Athena choose the s3tablescatalog catalog for your bucket, pick the namespace as the database and query the table with SQL.

Does S3 Tables support Spark?

Yes, on EMR, Glue or your own cluster, either through the Glue Data Catalog or directly with the Amazon S3 Tables Catalog for Apache Iceberg client library, using the table bucket ARN as the warehouse.

Can I use S3 Tables with PyIceberg or DuckDB?

Yes, through the Iceberg REST endpoint at https://s3tables.REGION.amazonaws.com/iceberg with SigV4 signing, or through the AWS Glue Iceberg REST endpoint for broader governance.

What is S3 Tables compaction?

An automatic job that merges small files into larger ones, 512 MB by default or any target from 64 to 512 MB, and applies pending deletes. It uses binpack, sort or z-order strategies and costs $0.002 per 1,000 objects plus $0.005 or $0.01 per GB processed.

How long does S3 Tables keep snapshots?

By default it keeps at least one snapshot and expires snapshots older than 120 hours (five days). You can raise or lower both values per table, which sets how far back you can time travel.

What is unreferenced file removal?

A table bucket setting that marks files no snapshot uses as noncurrent after 3 days and permanently deletes them after another 10 days by default. It keeps storage from filling up with leftovers from failed writes and expired snapshots.

Do S3 Tables support Intelligent-Tiering?

Yes. Intelligent-Tiering for S3 Tables moves data between Frequent Access ($0.0265 per GB-month), Infrequent Access ($0.0144) and Archive Instant Access ($0.0046) based on how often it is read.

Can S3 Tables be replicated to another Region?

Yes. Replication copies your tables to a table bucket in another Region or account, charged at $0.01 per 1,000 table updates and $0.005 per 1,000 replicated writes, plus data transfer and the destination's storage.

What is the difference between S3 Tables and S3 Metadata?

S3 Metadata is a feature that keeps a queryable table of the objects in a general purpose bucket, and it stores that table in a table bucket. S3 Tables is the general service you use for your own analytics tables.

What permissions does S3 Tables need?

IAM actions with the s3tables: prefix on table bucket and table ARNs, plus Lake Formation grants if Lake Formation governs the catalog, and KMS key permissions for both your role and the maintenance service principal on SSE-KMS buckets.

How many table buckets can I create?

100 per Region per account by default, each holding up to 10,000 namespaces and 10,000 tables. You can request increases through AWS Support.

Does S3 Tables support Delta Lake or Hudi?

No. S3 Tables stores Apache Iceberg tables only. Keep Delta Lake or Hudi tables in general purpose buckets, or convert them to Iceberg.

Do old snapshots cost extra in S3 Tables?

Indirectly. A snapshot keeps the data files it references, so while it is retained, files that newer snapshots replaced still count toward your storage and monitoring bill. With the default five-day retention this is small; raising retention to months on a table that changes heavily can add noticeably to storage.

Is S3 Tables a database?

Not quite. It is table storage with transactions and a catalog, but no query engine of its own. You bring the engine (Athena, Redshift, Spark, DuckDB), which makes it a lakehouse storage layer rather than a database server.

Can Snowflake read Amazon S3 Tables?

Yes. Since August 2026 Snowflake can connect directly to the S3 Tables Iceberg REST endpoint with a catalog integration and a catalog-linked database, using vended credentials. For Lake Formation permissions, connect through the AWS Glue Iceberg REST endpoint instead.

Is S3 Tables available in AWS GovCloud?

Yes, in AWS GovCloud (US-East) and (US-West) since February 2026. Table replication is not available in the GovCloud Regions.

What data types do S3 Tables support?

Apache Iceberg's types: boolean, int, long, float, double, decimal, date, time, timestamp and timestamptz, string, uuid, fixed and binary, plus nested struct, list and map. Your engine maps its own types onto them.

Can I use S3 Tables with Amazon QuickSight?

Yes. QuickSight connects through Athena, so once your table bucket is integrated with the Glue Data Catalog, you build an Athena dataset on the table and use it in your dashboards.

For readers preparing for an AWS certification

We have been covering AWS certifications alongside our fixes, so here is a short extra for readers studying for one. If you only came for the fix, you already have it; feel free to skip this part.

Exams that test this topic: Data Engineer – Associate • Solutions Architect – Associate (SAA-C03) • CloudOps Engineer – Associate (SOA-C03).

Here are the exam-style questions this topic tends to raise, with the reasoning you need to answer them:

1. An analytics team needs row-level updates and deletes on tables stored in Amazon S3, with compaction handled automatically and the least operational effort. What should it use?

Amazon S3 Tables (table buckets that store managed Apache Iceberg tables).

2. S3 Tables must be queryable from Amazon Athena. What must be enabled?

The integration with AWS analytics services, which exposes table buckets in the AWS Glue Data Catalog as s3tablescatalog.

3. A role with s3:* permissions gets AccessDenied on a table bucket. Why?

Table buckets use s3tables: IAM actions, which s3:* does not cover.

4. Historical data in S3 Tables is rarely queried. How can storage cost be reduced without moving it?

Use S3 Tables Intelligent-Tiering (Infrequent Access and Archive Instant Access tiers).

5. Creating a table in an SSE-KMS encrypted table bucket fails. What is the likely fix?

Allow the maintenance.s3tables.amazonaws.com principal kms:GenerateDataKey and kms:Decrypt in the key policy.

6. An analyst needs to query a table as it was two days ago. Which feature allows this, and what limits it?

Iceberg time travel, limited by snapshot retention (120 hours by default).

7. Which service can stream records into an S3 table without custom code?

Amazon Data Firehose.

Exam codes and dates change often. Our AWS certification changes page keeps track of what is current.

πŸ“š ALSO READ

Where to go next, from Redshift to KMS and replication fixes:

📌 Bookmark this; the price table, the worked costs and the maintenance settings are the parts you will come back for.

Two weeks later, the tickets table had taken about 9,000 status updates, one UPDATE statement at a time from the shop's ticketing app, and the S3 Tables line on Jake's bill was $1.71. The technicians had a dashboard showing which phones were waiting for parts, and Jake had his answer to "Is my phone ready?" in one query. The only setting Ethan changed was snapshot retention, raised to 30 days, after Jake asked whether they could see what the board looked like "last Tuesday, before Kevin marked everything as done."

📌 If you keep one line from this page

S3 Tables are managed Apache Iceberg tables in table buckets: $0.0265 per GB-month plus $0.025 per 1,000 objects and compaction from $0.005 per GB, with row updates, schema changes and time travel, and compaction, snapshot expiry and cleanup done for you.

Enable the integration · lowercase names · write through an engine, not by copying files.

Revision note. Written October 21, 2026. Prices are US East (N. Virginia) list prices on that date. We will update this page when S3 Tables prices, limits or features change.

Related