Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions s3files-lambda-sam/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Mount an S3 Bucket as a File System on AWS Lambda using Amazon S3 Files

This pattern mounts an Amazon S3 bucket as a file system on an AWS Lambda function using **Amazon S3 Files**, then reads CSV files with **pandas** using standard Python file I/O.

Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/s3files-lambda-sam

Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.

## Requirements

* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed
* [Python 3.13](https://www.python.org/downloads/) installed

## How it works

1. An S3 bucket is linked to an **S3 file system** (Amazon S3 Files), providing full POSIX file system semantics over S3 data.
2. A **mount target** is created in a private subnet, giving the Lambda function NFS access to the file system.
3. The Lambda function is configured with `FileSystemConfigs` pointing to the access point, mounting the S3 bucket at `/mnt/s3data`.
4. When invoked, Lambda reads a CSV file from `/mnt/s3data/input/` using `pandas.read_csv()` — a standard file path, no boto3 required.
5. It returns the row count, column names, and a preview of the first 5 rows as JSON.

## Build Instructions

Build the pandas Lambda layer targeting Linux x86_64 (Lambda's runtime), then remove pyarrow to stay within Lambda's 250MB unzipped layer limit:

```bash
pip install pandas \
--platform manylinux2014_x86_64 \
--target layer/python/ \
--implementation cp \
--python-version 3.13 \
--only-binary=:all:

# Remove pyarrow if present (not needed for CSV reads, exceeds layer size limit)
rm -rf layer/python/pyarrow

sam build
```

> The `--platform` flag ensures Linux-compatible wheels are downloaded regardless of your local OS (macOS, Windows, or Linux).

## Deployment Instructions

1. Clone the repository:
```bash
git clone https://github.com/aws-samples/serverless-patterns
```

2. Change to the pattern directory:
```bash
cd s3files-lambda-sam
```

3. Build (see Build Instructions above).

4. Deploy:
```bash
sam deploy --guided
```

5. During the prompts:
* Enter a stack name
* Enter the desired AWS Region
* Accept the default parameter values or adjust VPC CIDRs if needed
* Allow SAM CLI to create IAM roles with the required permissions

Once you have run `sam deploy --guided` once and saved arguments to `samconfig.toml`, you can use `sam deploy` for future deployments.

6. Note the outputs — you will need `DataBucketName` and `S3FilesReaderFunctionName` for testing.

## Testing

### Unit tests (no AWS required)

```bash
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install pytest pandas
pytest src/tests/ -v
```

### Integration test against a deployed stack

#### 1. Upload the sample CSV

```bash
BUCKET=$(aws cloudformation describe-stacks \
--stack-name <your-stack-name> \
--query "Stacks[0].Outputs[?OutputKey=='DataBucketName'].OutputValue" \
--output text)

aws s3 cp src/tests/sample_sales.csv s3://$BUCKET/lambda/input/sample_sales.csv
```

#### 2. Invoke the Lambda function

```bash
FUNCTION=$(aws cloudformation describe-stacks \
--stack-name <your-stack-name> \
--query "Stacks[0].Outputs[?OutputKey=='S3FilesReaderFunctionName'].OutputValue" \
--output text)

aws lambda invoke \
--function-name $FUNCTION \
--payload '{"file": "input/sample_sales.csv"}' \
--cli-binary-format raw-in-base64-out \
response.json

cat response.json
```

Expected response:

```json
{
"statusCode": 200,
"body": {
"file": "/mnt/s3data/input/sample_sales.csv",
"rows": 10,
"columns": ["region", "revenue", "units"],
"preview": [...]
}
}
```

#### 3. Check Lambda logs

```bash
sam logs --stack-name <your-stack-name> --tail
```

## Cleanup

1. Delete the stack:
```bash
aws cloudformation delete-stack --stack-name STACK_NAME
```

2. Confirm the stack has been deleted:
```bash
aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus"
```

----
Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.

SPDX-License-Identifier: MIT-0
69 changes: 69 additions & 0 deletions s3files-lambda-sam/example-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"title": "Mount an S3 Bucket as a File System on AWS Lambda using Amazon S3 Files",
"description": "This pattern mounts an Amazon S3 bucket as a file system on an AWS Lambda function using Amazon S3 Files, enabling standard Python file I/O to read S3 data — no S3 SDK calls required.",
"language": "Python",
"level": "200",
"framework": "AWS SAM",
"introBox": {
"headline": "How it works",
"text": [
"Amazon S3 Files (launched April 2026) is a shared file system built on Amazon EFS that provides full POSIX file system semantics over your S3 data. It lets file-based applications, agents, and tools work directly with S3 data without duplicating it or learning new APIs.",
"This pattern links an S3 bucket to an S3 file system and mounts it on a Lambda function at /mnt/s3data. When invoked, the Lambda function reads a CSV file from the mount path using pandas.read_csv() and returns the row count, column names, and a preview of the first 5 rows — all through standard Python file I/O, with no boto3 S3 calls.",
"This pattern deploys one S3 bucket, one S3 file system, one mount target, one S3 Files access point, one Lambda function with a pandas layer, and a VPC with a private subnet and VPC endpoints for S3."
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/s3files-lambda-sam",
"templateURL": "serverless-patterns/s3files-lambda-sam",
"projectFolder": "s3files-lambda-sam",
"templateFile": "template.yaml"
}
},
"resources": {
"bullets": [
{
"text": "Amazon S3 Files — product page",
"link": "https://aws.amazon.com/s3/features/files/"
},
{
"text": "Working with Amazon S3 Files — documentation",
"link": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files.html"
},
{
"text": "Mounting S3 file systems on AWS Lambda functions",
"link": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files-mounting-lambda.html"
},
{
"text": "Configuring file system access for Lambda functions",
"link": "https://docs.aws.amazon.com/lambda/latest/dg/configuration-filesystem.html"
}
]
},
"deploy": {
"text": [
"pip install pandas --platform manylinux2014_x86_64 --target layer/python/ --implementation cp --python-version 3.13 --only-binary=:all:",
"rm -rf layer/python/pyarrow",
"sam build",
"sam deploy --guided"
]
},
"testing": {
"text": [
"See the GitHub repo for detailed testing instructions."
]
},
"cleanup": {
"text": [
"Delete the stack: <code>aws cloudformation delete-stack --stack-name STACK_NAME</code>."
]
},
"authors": [
{
"name": "Serda Kasaci Yildirim",
"image": "https://drive.google.com/file/d/1rzVS1hrIMdqy6P9i7-o7OBLNc0xY0FVB/view?usp=sharing",
"bio": "Serda is a Solutions Architect at Amazon Web Services based in Vienna, focused on serverless technologies, event-driven architecture, and application modernization.",
"linkedin": "serdakasaci"
}
]
}
3 changes: 3 additions & 0 deletions s3files-lambda-sam/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytest>=8.0
pandas>=2.0
pyarrow>=14.0
51 changes: 51 additions & 0 deletions s3files-lambda-sam/src/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Amazon S3 Files + AWS Lambda

Demonstrates accessing an S3 bucket as a file system from Lambda using
Amazon S3 Files. Files are read and written via standard Python file I/O
at the local mount path — no boto3 S3 calls needed.

The S3 bucket is mounted at /mnt/s3data via the S3 Files file system.
"""

import json
import logging
import os

import pandas as pd

logger = logging.getLogger()
logger.setLevel(os.environ.get("LOG_LEVEL", "INFO"))

MOUNT_PATH = os.environ.get("MOUNT_PATH", "/mnt/s3data")


def lambda_handler(event, context):
"""
Expected event:
{
"file": "input/sample_sales.csv" # path relative to the S3 Files mount root
}
"""
file_key = event.get("file")
if not file_key:
return {"statusCode": 400, "body": {"error": "Missing required field: 'file'"}}

input_path = os.path.join(MOUNT_PATH, file_key)

if not os.path.exists(input_path):
return {"statusCode": 404, "body": {"error": f"File not found: {input_path}"}}

# Read the CSV directly from the S3 Files mount using standard file I/O
df = pd.read_csv(input_path)
logger.info("Read %s: %d rows, %d columns", input_path, len(df), len(df.columns))

return {
"statusCode": 200,
"body": {
"file": input_path,
"rows": len(df),
"columns": list(df.columns),
"preview": df.head(5).to_dict(orient="records"),
},
}
Empty file.
11 changes: 11 additions & 0 deletions s3files-lambda-sam/src/tests/sample_sales.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
region,revenue,units
North,1000,10
South,2000,20
North,500,5
East,750,8
South,300,3
West,1200,15
East,900,12
West,450,6
North,800,9
South,1100,11
Loading