
Building Modern Data Lakes with Amazon S3 Tables and Glue: A Complete ETL Implementation Guide with MCP Integration
Amazon S3 Tables represents a paradigm shift in modern data lake architecture. By combining Amazon S3's infinite scalability with Apache Iceberg's ACID transaction capabilities, Amazon S3 Tables delivers a fully managed table format that simplifies data lake operations while maintaining enterprise-grade performance and reliability. This guide explores building complete ETL pipelines and demonstrates how to leverage MCP servers with LLMs for intelligent data querying and analysis.
Introduction
Amazon S3 Tables bucket represents a paradigm shift in how we build and manage data lakes. By combining the scalability of Amazon S3 with the ACID transaction capabilities of Apache Iceberg, Amazon S3 Tables provides a managed table format that simplifies data lake operations while maintaining enterprise-grade performance and reliability.
Traditional data lakes struggle with data consistency, schema evolution, and the "small files problem" that impacts query performance. Amazon S3 Tables addresses these challenges by providing automatic table optimization, compaction, and metadata management while maintaining full compatibility with the open Iceberg format.
In this comprehensive guide, we'll walk through implementing a complete ETL pipeline using Amazon S3 Tables, demonstrating both full load and incremental data processing patterns essential for modern data architectures. We'll cover real-world scenarios including late-arriving data, schema evolution, and performance optimization through strategic partitioning.
Our implementation uses AWS Glue's PySpark environment, leveraging its serverless compute model and native Amazon S3 Tables integration. The Glue job has been developed in PySpark, utilizing the latest optimizations for distributed data processing. We'll explore everything from initial setup to advanced optimization techniques, error handling, and monitoring strategies.
The full Git repository with all scripts, configuration files, and sample data will be provided, allowing you to follow along and adapt these solutions to your specific use cases.
Understanding Apache Iceberg and Amazon S3 Tables
Apache Iceberg is an open-source table format designed to handle massive datasets in data lakes, providing ACID transactions, schema evolution, and time travel capabilities that traditional file formats. Amazon S3 Tables builds on Iceberg's foundation, offering a fully managed service that simplifies data lake operations while maintaining compatibility with popular analytics engines like Spark, Trino, and Athena. Together, they solve critical challenges in modern data architecture by enabling reliable, scalable analytics on petabyte-scale datasets stored in AWS S3, with features like automatic compaction, metadata management, and seamless integration with the AWS ecosystem.
Apache Iceberg: The Foundation
Apache Iceberg is an open-source table format designed for large-scale analytical datasets. Unlike traditional data lake storage formats, Iceberg provides:
Table-level Operations: Treats collections of files as unified tables with atomic operations
- Hidden Partitioning: Partition data without exposing partition structure to queries
- Snapshot Isolation: Each table operation creates a new snapshot, enabling time travel and rollback
- Schema Evolution: Add, drop, or rename columns safely without rewriting data
- Metadata Management: Comprehensive metadata tracking for performance optimization
Amazon S3 Tables: Managed Iceberg at Scale
Amazon S3 Tables is a fully managed service that provides table-level abstractions over your Amazon S3 data lake. Built on Apache Iceberg, it offers:
- ACID Transactions: Ensure data consistency across concurrent operations
- Schema Evolution: Modify table schemas without breaking existing queries
- Time Travel: Query historical versions of your data
- Efficient Querying: Optimized for analytical workloads with partition pruning
- Automatic Optimization: Built-in compaction and maintenance operations
The key advantage of Amazon S3 Tables is that AWS manages the Iceberg metadata layer, eliminating the operational overhead of maintaining catalogs, handling concurrent writes, and optimizing table performance.
Key Benefits
- Simplified Data Management: No need to manage Iceberg metadata manually
- Performance Optimization: Automatic file compaction and partition management
- Cost Efficiency Pay only for storage and compute, with optimized data layouts
- Integration: Native integration with AWS analytics services
Ideal Use Cases
This solution particularly benefits organizations that need to:
- Modernize Legacy Systems: Migrate from traditional data warehouses
- Handle Mixed Workloads: Support both analytical and operational use cases
- Ensure Data Quality: Maintain strict data integrity requirements
- Scale Efficiently: Grow data infrastructure without linear cost increases
- Reduce Complexity: Minimize operational overhead while maximizing capabilities
Architecture Overview
Our demo implementation showcases a typical data lake ETL pattern:

Components
After the infrastructure is deployed using the scripts in the repository, our solution consists of the following components:
- Source Data: Product data stored in AWS S3 bucket as Parquet files
- AWS Glue: Serverless ETL service for data processing
- Amazon S3 Tables: Managed Iceberg tables for structured data storage
- CloudFormation: Infrastructure as Code for reproducible deployments
Deployment Instructions
To deploy this example, clone the repository and execute the scripts in the infrastructure folder in the following order:
1. Setup Amazon S3 Buckets
Run the following script to create a Artifacts and Data Lake bucket
./01-setup-s3-buckets.sh This script creates buckets for data and artifacts and uploads demo datasets (
demo1_products.parquet and demo400_products.parquet ).2. Deploy Infrastructure
Run the following script to create Amazon S3 Tables bucket and required resources
./02-deploy.sh dev This script deploys the CloudFormation stack that creates Amazon S3 Tables, IAM roles for AWS Glue jobs, and other required resources.

Amazon S3 Tables Bucket view after creation

Note: Very important to Enable integration with AWS analytical services

3. Create AWS Glue Job
Run the following script to create glue job
./03-create-glue-job.sh This script creates the AWS Glue job for ETL processing.

4. Execute AWS Glue Job Run Commands
This script contains commands to run the glue job with different parameters incremental and full load.
./04-job-run-commands.sh 
Here you can see the glue Job output logs in the Amazon CloudWatch shows the details of the load

After the data is loaded we can query our Amazon S3 Table via Amazon Athena using SQL
SQL
SELECT * FROM "poc_main_dev" limit 10;
Here is the results of the query

To take this even further, we'll incorporate the AWS MCP tool, which lets you query your AWS tables using natural language through LLMs. You can use any MCP-compatible client—I've chosen, of course, AWS Kiro. Below is the MCP configuration I used.
Amazon S3 Tables with MCP go beyond simple queries enabling transactional reads/writes, metadata access, and deep integration with data lake tools, as outlined in AWS documentation .
Prompt: Get my S3 tables names

Prompt: Get 3 records from the table and display the results in table format.

Deep drive data schema design
This product data schema is designed for analytical workloads to demonstrate
Python
CREATE TABLE IF NOT EXISTS raw.productdb.products (product_id STRING, -- Primary key for product identificationproduct_name STRING, -- Human-readable product nameproduct_description STRING, -- Detailed product informationproduct_category STRING, -- Product categorizationproduct_price DOUBLE, -- Current product pricesale_date DATE, -- Date of sale transactionsales_amount DOUBLE, -- Total sales amountcreated_at TIMESTAMP, -- Record creation timestampupdated_at TIMESTAMP -- Last modification timestamp) USING ICEBERG
Schema Design Principles
- Immutable Keys: `product_id` serves as the primary key
- Audit Trail: `created_at` and `updated_at` for data lineage
- Type Safety: Proper data types for numerical and date fields
- Analytical Focus: Schema optimized for common analytical queries
Partitioning Strategy
Effective partitioning is crucial for query performance
SQL
ALTER TABLE raw.productdb.productsADD PARTITION FIELD bucket(4, product_id)
Partitioning Benefits:
- Query Performance: Reduces data scanning for filtered queries
- Parallel Processing: Enables concurrent operations across partitions
- Cost Optimization: Minimizes data transfer and compute costs
- Maintenance Efficiency: Simplifies data lifecycle management
ETL Job Implementation
This Glue ETL job supports both full load and incremental processing
Full Load Processing and Characteristics
- Complete Refresh: Replaces all existing data
- Partition Overwrite: Efficient replacement of data partitions
- Atomic Operations: Ensures consistency during large data loads
- Verification: Built-in data validation and counting
Python
def full_load(df):"""Perform full load - overwrite all partitions"""print("Performing full load (overwrite partitions)...")# Use Iceberg's overwritePartitions for efficient full loaddf.writeTo(f"raw.{FULL_TABLE_NAME}").overwritePartitions()# Verify loadfinal_count = spark.sql(f"SELECT COUNT(*) as count FROM raw.{FULL_TABLE_NAME}").collect()[0]['count']print(f"✓ Full load completed: {final_count:,} records in table")
Incremental Processing with MERGE
MERGE Operation Benefits
- Upsert Capability: Handles both updates and inserts in a single operation
- ACID Compliance: Ensures data consistency across concurrent operations
- Performance Optimization: Minimizes data movement and processing overhead
- Audit Trail: Maintains proper timestamps for data lineage
Python
def incremental_load(df):"""Perform incremental load using MERGE operations"""merge_sql = f"""MERGE INTO raw.{FULL_TABLE_NAME} AS targetUSING source_data AS sourceON target.product_id = source.product_idWHEN MATCHED THENUPDATE SETproduct_name = source.product_name,product_description = source.product_description,product_category = source.product_category,product_price = source.product_price,sale_date = source.sale_date,sales_amount = source.sales_amount,updated_at = source.updated_atWHEN NOT MATCHED THENINSERT (product_id, product_name, product_description,product_category, product_price, sale_date,sales_amount, created_at, updated_at)VALUES (source.product_id, source.product_name, source.product_description,source.product_category, source.product_price, source.sale_date,source.sales_amount, source.created_at, source.updated_at)spark.sql(merge_sql)
Conclusion
Amazon S3 Tables with Apache Iceberg provides a powerful foundation for modern data lake architectures. This implementation demonstrates how to build production-ready ETL pipelines that handle both batch and incremental processing while maintaining ACID compliance and optimal performance.By leveraging the Model Context Protocol (MCP) server to query and interact with our data throughout the development process, we were able to streamline data exploration, validation, and pipeline testing. The MCP server's ability to seamlessly bridge our data infrastructure with development workflows proved invaluable for rapid iteration and debugging of our Iceberg-based solutions.The combination of managed infrastructure, automated optimization, flexible querying capabilities, and integrated development tools like MCP makes Amazon S3 Tables an excellent choice for organizations looking to modernize their data lake architecture without the operational complexity of managing Iceberg metadata manually. This approach not only reduces infrastructure overhead but also accelerates development cycles through better tooling integration and data accessibility.
Resources
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article