AWS EFS Throughput Modes Explained: Pick the Right One
Benchmark data for EFS Bursting vs Elastic vs Provisioned throughput modes. Includes cost comparisons, fio results, and a decision framework to avoid performance surprises.

Introduction
AWS Elastic File System (EFS) provides shared file storage for EC2 instances, containers, and Lambda functions. However, its performance characteristics are frequently misunderstood, leading to either unexplained latency spikes when burst credits deplete or overspending on provisioned throughput that goes unused.
EFS offers three throughput modes (Bursting, Elastic, and Provisioned) and two performance modes (General Purpose and Max I/O). Selecting the right combination reduces costs by 40-60% while eliminating performance issues. This guide provides benchmark data and decision frameworks for each combination.
Throughput Mode Comparison
| Mode | How It Works | Best For | Cost Structure |
|---|---|---|---|
| Bursting | Throughput scales with stored data | Spikey workloads, > 1TB stored | Storage only |
| Elastic | Auto-scales to demand, pay per use | Unpredictable workloads | Storage + throughput used |
| Provisioned | Fixed throughput regardless of size | Consistent high-throughput needs | Storage + provisioned rate |
Bursting Mode Credit Mechanics
| Storage Size | Baseline Throughput | Burst Throughput | Burst Duration (full credits) |
|---|---|---|---|
| 100 GB | 5 MB/s | 100 MB/s | 72 minutes |
| 500 GB | 25 MB/s | 100 MB/s | 360 minutes |
| 1 TB | 50 MB/s | 100 MB/s | Indefinite |
| 5 TB | 250 MB/s | 500 MB/s | Indefinite |
| 10 TB | 500 MB/s | 1,000 MB/s | Indefinite |
Critical insight: For file systems smaller than 1 TB, bursting mode eventually depletes credits during sustained workloads. This is the #1 cause of unexpected EFS performance degradation.
Benchmark Results
Sequential Read Throughput
Tested with fio across different file sizes and throughput modes on m6i.2xlarge instances:
# Benchmark command
fio --name=seq-read \
--directory=/mnt/efs \
--rw=read \
--bs=1M \
--numjobs=4 \
--iodepth=32 \
--size=10G \
--runtime=300 \
--time_based \
--group_reporting
| Configuration | Throughput (MB/s) | Latency (avg) | IOPS |
|---|---|---|---|
| Bursting (100 GB, with credits) | 100 | 2.5ms | 100 |
| Bursting (100 GB, no credits) | 5 | 50ms | 5 |
| Bursting (1 TB, sustained) | 50 | 5ms | 50 |
| Elastic (auto-scaled) | 350 | 1.8ms | 350 |
| Provisioned (256 MB/s) | 256 | 2.0ms | 256 |
| Provisioned (1024 MB/s) | 1,024 | 1.2ms | 1,024 |
Random Read IOPS (4K Block Size)
| Performance Mode | IOPS (4K reads) | Latency (avg) | Latency (p99) |
|---|---|---|---|
| General Purpose | 35,000 | 0.6ms | 2.5ms |
| General Purpose (One Zone) | 35,000 | 0.4ms | 1.8ms |
| Max I/O | 500,000+ | 1.0ms | 5.0ms |
Metadata Operations
| Operation | General Purpose | Max I/O | EBS (reference) |
|---|---|---|---|
| File create | 1.5ms | 3.0ms | 0.2ms |
| File stat | 0.5ms | 1.0ms | 0.05ms |
| Directory listing (1000 files) | 15ms | 25ms | 2ms |
| File rename | 2.0ms | 4.0ms | 0.1ms |
Performance Mode Decision
| Characteristic | General Purpose | Max I/O |
|---|---|---|
| Latency | Lower (< 1ms for reads) | Higher (1-5ms) |
| IOPS ceiling | 35,000 | 500,000+ |
| Metadata ops | Faster | Slower |
| Ideal workload | Web serving, CMS, CI/CD | Big data, genomics, ML training |
| Client count | < 100 concurrent | 100-1000+ concurrent |
Cost Analysis
Monthly Cost Comparison (1 TB stored, 100 MB/s average throughput)
| Throughput Mode | Storage Cost | Throughput Cost | Total Monthly |
|---|---|---|---|
| Bursting | $300 | $0 (included) | $300 |
| Elastic | $300 | $270* | $570 |
| Provisioned (100 MB/s) | $300 | $600 | $900 |
| Provisioned (256 MB/s) | $300 | $1,536 | $1,836 |
*Elastic mode: $0.04/GB transferred for reads, $0.06/GB for writes
When Each Mode Saves Money
| Scenario | Cheapest Mode | Monthly Cost |
|---|---|---|
| 5 TB stored, 50 MB/s needed | Bursting | $1,500 |
| 100 GB stored, 100 MB/s needed | Provisioned | $630 |
| 500 GB stored, variable (0-500 MB/s) | Elastic | $150 + usage |
| 2 TB stored, 200 MB/s needed | Provisioned | $1,800 |
Monitoring EFS Performance
CloudWatch Metrics
# Monitor burst credit balance (critical for bursting mode)
aws cloudwatch get-metric-statistics \
--namespace AWS/EFS \
--metric-name BurstCreditBalance \
--dimensions Name=FileSystemId,Value=fs-0123456789 \
--start-time "$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%S)" \
--end-time "$(date -u +%Y-%m-%dT%H:%M:%S)" \
--period 3600 \
--statistics Minimum
# Monitor throughput utilization
aws cloudwatch get-metric-statistics \
--namespace AWS/EFS \
--metric-name TotalIOBytes \
--dimensions Name=FileSystemId,Value=fs-0123456789 \
--start-time "$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S)" \
--end-time "$(date -u +%Y-%m-%dT%H:%M:%S)" \
--period 60 \
--statistics Sum
Alert for Burst Credit Depletion
aws cloudwatch put-metric-alarm \
--alarm-name "EFS-BurstCredits-Low" \
--namespace AWS/EFS \
--metric-name BurstCreditBalance \
--dimensions Name=FileSystemId,Value=fs-0123456789 \
--statistic Minimum \
--period 300 \
--threshold 1000000000000 \
--comparison-operator LessThanThreshold \
--evaluation-periods 3 \
--alarm-actions "arn:aws:sns:us-east-1:123456789012:ops-alerts" \
--alarm-description "EFS burst credits below 1TB - performance degradation imminent"
Mount Options for Performance
# Optimized mount options for high-throughput workloads
sudo mount -t nfs4 \
-o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport \
fs-0123456789.efs.us-east-1.amazonaws.com:/ /mnt/efs
# /etc/fstab entry
fs-0123456789.efs.us-east-1.amazonaws.com:/ /mnt/efs nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev 0 0
Mount Option Impact
| Option | Default | Optimized | Impact |
|---|---|---|---|
| rsize | 1 MB | 1 MB | Max read buffer (already optimal) |
| wsize | 1 MB | 1 MB | Max write buffer |
| timeo | 600 | 600 | Timeout before retry (deciseconds) |
| retrans | 2 | 2 | Retry count |
| noresvport | No | Yes | Allows connection recovery without unmount |
EFS with Kubernetes (EFS CSI Driver)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: efs-sc
provisioner: efs.csi.aws.com
parameters:
provisioningMode: efs-ap
fileSystemId: fs-0123456789
directoryPerms: "700"
uid: "1000"
gid: "1000"
basePath: "/dynamic-pv"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-data
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 50Gi
Decision Framework
Is your stored data > 1 TB?
├── Yes: Is throughput demand consistent?
│ ├── Yes (> baseline): Use Provisioned
│ └── No (spikey): Bursting works (baseline = size_TB * 50 MB/s)
└── No (< 1 TB):
├── Predictable throughput need: Use Provisioned
├── Unpredictable/variable: Use Elastic
└── Very low throughput (< 5 MB/s): Bursting with monitoring
Frequently Asked Questions
What are the EFS throughput modes?
AWS EFS offers three throughput modes: Bursting (throughput scales with stored data size), Elastic (auto-scales to demand with per-GB-transferred billing), and Provisioned (fixed throughput you configure regardless of file system size). Each mode has different cost structures and performance characteristics.
When should I use Elastic throughput vs Provisioned?
Use Elastic throughput when your workload is unpredictable or has variable demand—it auto-scales from 0 to 10+ GB/s and you only pay for what you use ($0.04/GB read, $0.06/GB write). Use Provisioned when you have consistent, predictable high-throughput needs, as it is cheaper than Elastic for steady-state workloads above approximately 100 MB/s sustained.
How does EFS performance scale with file system size?
In Bursting mode, baseline throughput is 50 MB/s per TB stored. A 100 GB file system gets only 5 MB/s baseline, while a 5 TB file system gets 250 MB/s. File systems under 1 TB will eventually deplete burst credits during sustained workloads, which is the most common cause of unexpected EFS performance degradation.
What's the maximum throughput for EFS?
EFS can deliver over 10 GB/s in Elastic mode and up to 1,024 MB/s per provisioned configuration. For IOPS, General Purpose mode supports up to 35,000 IOPS with sub-millisecond latency, while Max I/O mode supports 500,000+ IOPS at slightly higher latency (1-5ms).
Should I use General Purpose or Max I/O performance mode?
General Purpose mode suits 90% of workloads with lower latency (under 1ms for reads) and faster metadata operations. Choose Max I/O only for massively parallel workloads (100-1000+ concurrent clients) like big data processing, genomics, or ML training where you need 500,000+ IOPS and can tolerate higher latency.
Key Takeaways
- Bursting mode only works reliably for file systems above 1 TB where baseline throughput meets demand; smaller file systems will deplete credits during sustained workloads.
- Elastic mode is ideal for unpredictable workloads providing automatic scaling from 0 to 10+ GB/s without provisioning, at a per-GB-transferred cost.
- Provisioned mode is cheapest for consistent high-throughput when you know your steady-state throughput needs and can commit to a fixed rate.
- Monitor BurstCreditBalance as a critical metric and alert when credits drop below 1 TB to prevent sudden performance degradation.
- General Purpose performance mode suits 90% of workloads with sub-millisecond latency up to 35,000 IOPS; only use Max I/O for massively parallel access patterns.
- Use noresvport mount option to ensure NFS connections can recover after brief network interruptions without requiring a full unmount.
- EFS metadata operations are 10-30x slower than EBS making it unsuitable for workloads with heavy file creation, renaming, or directory listing operations.
Recommended reading

Per-Team Cost Allocation in Shared Kubernetes Clusters: From Chaos to Clarity
Implementing accurate per-namespace cost allocation in multi-tenant Kubernetes clusters, covering request vs. usage attribution, shared resource amortization, and building showback dashboards that drive accountability.

Measuring and Eliminating Toil: From 40% to 12% of Engineering Time
A systematic approach to identifying, measuring, and automating toil—the repetitive operational work that scales linearly with service growth and prevents engineers from doing creative work.

Serverless Postgres in Production: Branching, Scale-to-Zero, and the End of Database Provisioning
Running Neon serverless Postgres in production for 8 months — covering database branching workflows, scale-to-zero economics, connection pooling, and migration from RDS.

Comments
No comments yet. Be the first to share your thoughts.