Serverless ETL/ELT Architecture with S3, EventBridge, Lambda, Step Functions, and Glue
Cloud

Serverless ETL/ELT Architecture with S3, EventBridge, Lambda, Step Functions, and Glue

March 30, 2026 5 min read Source: devto

Serverless ETL Architecture: S3, Lambda, Step Functions Guide

Modern data pipelines need to scale automatically and handle unpredictable workloads. Traditional ETL systems often waste resources during low-traffic periods and struggle with sudden spikes.

Serverless ETL architecture solves these problems. It scales to zero when idle and handles massive workloads without manual intervention. AWS provides all the tools you need to build robust, cost-effective data pipelines.

Why Choose Serverless for ETL Pipelines

Serverless ETL offers several key advantages over traditional approaches:

Traditional ETL systems require constant monitoring and capacity planning. Serverless eliminates these operational burdens while reducing costs by up to 70% for variable workloads.

Core Components of Serverless ETL

Amazon S3: The Data Foundation

S3 serves as both source and destination for your data pipeline. It triggers processing when new files arrive and stores transformed results.

Key S3 features for ETL:


# Configure S3 event notification
aws s3api put-bucket-notification-configuration \
  --bucket my-etl-bucket \
  --notification-configuration file://notification.json

EventBridge: The Event Router

EventBridge decouples your pipeline components and enables complex routing logic. It receives S3 events and routes them to appropriate processing services.

EventBridge patterns for ETL:


{
  "Rules": [{
    "Name": "ProcessCSVFiles",
    "EventPattern": {
      "source": ["aws.s3"],
      "detail": {
        "eventName": ["ObjectCreated:Put"],
        "requestParameters": {
          "key": [{"suffix": ".csv"}]
        }
      }
    },
    "Targets": [{
      "Id": "1",
      "Arn": "arn:aws:lambda:region:account:function:ProcessCSV"
    }]
  }]
}

Lambda: Lightweight Processing

Lambda handles small to medium data transformations with sub-second startup times. It's perfect for file validation, format conversion, and simple aggregations.


import json
import boto3
import pandas as pd

def lambda_handler(event, context):
    s3_client = boto3.client('s3')
    
    # Extract S3 details from event
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']
    
    # Download and process file
    obj = s3_client.get_object(Bucket=bucket, Key=key)
    df = pd.read_csv(obj['Body'])
    
    # Simple transformation
    df['processed_date'] = pd.Timestamp.now()
    df = df.dropna()
    
    # Upload transformed data
    output_key = f"processed/{key}"
    df.to_csv(f"s3://{bucket}/{output_key}", index=False)
    
    return {
        'statusCode': 200,
        'body': json.dumps(f'Processed {len(df)} records')
    }

Step Functions: Workflow Orchestration

Step Functions coordinate complex ETL workflows with multiple stages, error handling, and parallel processing.


{
  "Comment": "ETL Pipeline with error handling",
  "StartAt": "ValidateInput",
  "States": {
    "ValidateInput": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:region:account:function:ValidateData",
      "Next": "ProcessData",
      "Catch": [{
        "ErrorEquals": ["States.TaskFailed"],
        "Next": "HandleError"
      }]
    },
    "ProcessData": {
      "Type": "Parallel",
      "Branches": [
        {
          "StartAt": "TransformCustomers",
          "States": {
            "TransformCustomers": {
              "Type": "Task",
              "Resource": "arn:aws:states:::glue:startJobRun.sync",
              "Parameters": {
                "JobName": "customer-transform"
              },
              "End": true
            }
          }
        },
        {
          "StartAt": "TransformOrders", 
          "States": {
            "TransformOrders": {
              "Type": "Task",
              "Resource": "arn:aws:states:::glue:startJobRun.sync",
              "Parameters": {
                "JobName": "order-transform"
              },
              "End": true
            }
          }
        }
      ],
      "Next": "LoadToWarehouse"
    }
  }
}

AWS Glue: Heavy-Duty Processing

Glue handles large-scale transformations that exceed Lambda's limits. It provides automatic schema discovery and built-in connectors for popular data sources.


import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job

args = getResolvedOptions(sys.argv, ['JOB_NAME', 'INPUT_PATH', 'OUTPUT_PATH'])
sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

# Read data from S3
datasource = glueContext.create_dynamic_frame.from_options(
    format_options={"multiline": False},
    connection_type="s3",
    format="json",
    connection_options={
        "paths": [args['INPUT_PATH']],
        "recurse": True
    }
)

# Apply transformations
transformed = datasource.apply_mapping([
    ("customer_id", "string", "customer_id", "string"),
    ("order_date", "string", "order_date", "timestamp"),
    ("amount", "double", "amount", "decimal(10,2)")
])

# Write to data warehouse
glueContext.write_dynamic_frame.from_options(
    frame=transformed,
    connection_type="s3",
    connection_options={"path": args['OUTPUT_PATH']},
    format="parquet"
)

job.commit()

Architecture Patterns and Best Practices

Event-Driven Processing

Design your pipeline to react to data arrival automatically. Use S3 events to trigger processing and EventBridge to route events based on file type or size.

Error Handling Strategy

Implement comprehensive error handling at every stage:

Cost Optimization Tips

Security Considerations

Common Pitfalls to Avoid

Lambda timeout issues: Large files can exceed Lambda's 15-minute limit. Use Glue for heavy processing instead.

Concurrent execution limits: Lambda has default concurrency limits. Monitor and request increases for high-volume pipelines.

Step Functions state machine limits: Complex workflows can hit state machine quotas. Break large workflows into smaller, composable pieces.

Glue job startup time: Glue jobs take 2-3 minutes to start. Use Lambda for time-sensitive processing.

Monitoring and Observability

Implement comprehensive monitoring across all pipeline components:


import boto3

def publish_metrics(metric_name, value, unit='Count'):
    cloudwatch = boto3.client('cloudwatch')
    cloudwatch.put_metric_data(
        Namespace='ETL/Pipeline',
        MetricData=[{
            'MetricName': metric_name,
            'Value': value,
            'Unit': unit
        }]
    )

Set up CloudWatch dashboards to track:

Key Takeaways

Serverless ETL architecture provides automatic scaling, reduced operational overhead, and cost efficiency for modern data pipelines. The combination of S3, EventBridge, Lambda, Step Functions, and Glue creates a powerful, flexible system.

Start with simple Lambda transformations and gradually add Step Functions orchestration as complexity grows. Always implement proper error handling and monitoring from day one.

This architecture scales from gigabytes to petabytes while maintaining consistent performance and reliability. Your team can focus on business logic instead of infrastructure management.