AWS Reserved Instances vs Savings Plans vs Spot: A Practical Pricing Guide
AWS gives you three ways to pay less than on-demand pricing for compute: Reserved Instances, Savings Plans, and Spot Instances. Each trades something different for the discount. RIs and Savings Plans trade commitment. Spot trades reliability.
Most teams pick one and ignore the others. That leaves money on the table. The real savings come from layering all three based on workload characteristics. This guide covers how each works, when to use it, and how to combine them into a strategy that cuts your compute bill by 50-70%.
Quick Comparison
| Factor | Reserved Instances | Savings Plans | Spot Instances |
|---|---|---|---|
| Max discount | Up to 72% | Up to 72% (EC2 Instance SP) | Up to 90% |
| Commitment | 1 or 3 years | 1 or 3 years | None |
| Risk | Financial (pay even if unused) | Financial (pay even if unused) | Operational (2-min interruption notice) |
| Flexibility | Low (locked to instance type/region) | Medium to high | High (no commitment) |
| Management overhead | High (track expirations, exchanges) | Low (auto-applies) | Medium (interruption handling) |
| Applies to | EC2, RDS, ElastiCache, Redshift, OpenSearch | EC2, Fargate, Lambda, SageMaker | EC2 only |
| Payment options | All Upfront, Partial, No Upfront | All Upfront, Partial, No Upfront | Pay market price per hour |
| Best for | Stable, predictable workloads | Broad compute coverage | Fault-tolerant, flexible workloads |
Reserved Instances: Maximum Discount, Minimum Flexibility
Reserved Instances are the oldest commitment model. You commit to a specific instance configuration for 1 or 3 years, and AWS gives you a discounted hourly rate.
Standard vs Convertible
Standard RIs offer the deepest discounts (up to 72% off on-demand for 3-year all-upfront). The catch: you cannot change the instance family. If you buy a 3-year Standard RI for m6i.xlarge and later want to move to m7g.xlarge, that RI is stuck. You can modify the Availability Zone and instance size within the same family, but not the family itself. You can sell unused Standard RIs on the Reserved Instance Marketplace.
Convertible RIs offer lower discounts (up to 66% off on-demand for 3-year all-upfront). The upside: you can exchange them for different instance families, operating systems, or tenancies. You cannot sell Convertible RIs on the Marketplace.
Zonal vs Regional
Zonal RIs reserve capacity in a specific Availability Zone. You get a capacity reservation, meaning AWS guarantees that instance will be available when you need it. The discount applies only in that AZ.
Regional RIs apply the discount across all AZs in a region. More flexible, but no capacity reservation. For most workloads, regional RIs are the better choice unless you have strict availability requirements.
Real Pricing: m7g.xlarge in us-east-1
| Pricing model | Hourly rate | Monthly cost | Savings vs on-demand |
|---|---|---|---|
| On-demand | $0.1632 | ~$119 | 0% |
| 1-yr Standard RI (No Upfront) | ~$0.1050 | ~$77 | ~36% |
| 1-yr Standard RI (All Upfront) | ~$0.0950 | ~$69 | ~42% |
| 3-yr Standard RI (All Upfront) | ~$0.0570 | ~$42 | ~65% |
| 3-yr Convertible RI (All Upfront) | ~$0.0620 | ~$45 | ~62% |
When RIs Still Make Sense
Reserved Instances are the right choice for services that Savings Plans do not cover: RDS, ElastiCache, OpenSearch, and Redshift. For EC2, Savings Plans have largely replaced RIs for most use cases because they are simpler to manage and nearly as deep on discounts.
Savings Plans: The Simpler Commitment
Savings Plans launched in 2019 as a response to the complexity of Reserved Instances. Instead of committing to a specific instance, you commit to a dollar amount of compute usage per hour. AWS automatically applies the discount to your highest-cost usage first.
Three Types
1. Compute Savings Plans (most flexible)
- Applies to EC2, Fargate, and Lambda
- Any instance family, size, OS, tenancy, or region
- Discount: up to 66% (3-year, all upfront)
- Automatically applies to your most expensive eligible usage
2. EC2 Instance Savings Plans (deeper discount)
- Applies to EC2 only
- Locked to a specific instance family and region (e.g., m7g in us-east-1)
- Flexible on size, OS, and tenancy within that family
- Discount: up to 72% (3-year, all upfront)
3. SageMaker Savings Plans
- Applies to SageMaker only
- Any instance family, size, or region
- Discount: up to 64%
The Flexibility Tax
Compute Savings Plans cost roughly 5-7% more than EC2 Instance Savings Plans for the same workload. On a $10,000/month compute spend, that is $500-700/month in additional cost for the flexibility to change instance families or regions without losing your discount.
For most teams, that flexibility premium is worth it. Architecture changes happen. Graviton migrations happen. Region expansions happen. Locking into a specific instance family for 3 years is a bet that your infrastructure won’t change, and it usually does.
Checking Your Savings Plan Utilization
Before buying more Savings Plans, check how well your existing ones are being used:
aws ce get-savings-plans-utilization \
--time-period Start=$(date -u -d '30 days ago' +%Y-%m-%d),End=$(date -u +%Y-%m-%d) \
--query 'Total.{Utilization:UtilizationPercentage,Used:UsedCommitment,Total:TotalCommitment}'
Anything below 90% utilization means you over-committed. Address that before buying more.
Checking Your Savings Plan Coverage
See what percentage of your eligible spend is covered:
aws ce get-savings-plans-coverage \
--time-period Start=$(date -u -d '30 days ago' +%Y-%m-%d),End=$(date -u +%Y-%m-%d) \
--granularity MONTHLY \
--query 'SavingsPlansCoverages[].{Period:TimePeriod.Start,Coverage:CoveragePercentage}'
Spot Instances: Maximum Savings, Zero Commitment
Spot Instances let you use spare EC2 capacity at discounts of 50-90% off on-demand pricing. The trade-off: AWS can reclaim your instance with a 2-minute warning when it needs the capacity back.
How Spot Pricing Works
Spot pricing is no longer a bidding system. AWS sets the Spot price based on long-term supply and demand trends for each instance type in each Availability Zone. Prices are more stable than they used to be, but they still fluctuate.
You set a maximum price you are willing to pay. If the Spot price exceeds your max, your instance gets interrupted. In practice, most teams set the max to the on-demand price and rely on the market to provide savings.
Interruption Rates
AWS reports that the average interruption rate across all instance types and regions is less than 5%. But that is an average. Your actual rate depends heavily on what you run and where:
- General-purpose instances (m7g, m6i) in major regions: typically 2-5% interruption rate
- Compute-optimized (c7g, c6i): similar range, slightly higher in popular AZs
- GPU instances (p5, g6): significantly higher, sometimes 10-20%
- Older generation instances: lower interruption rates because fewer people compete for them
The Spot Instance Advisor shows trailing 30-day interruption rates and savings for each instance type: https://aws.amazon.com/ec2/spot/instance-advisor/
Handling Interruptions
Design for interruption from the start. Do not bolt it on later.
Instance metadata check (poll every 5 seconds):
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/spot/instance-action
If this returns a JSON response with an “action” field, your instance is being interrupted. If it returns a 404, you are fine.
Key patterns for Spot resilience:
- Checkpoint progress to S3 or DynamoDB at regular intervals
- Use Auto Scaling Groups with mixed instance types and Spot allocation strategy set to
capacity-optimized - Spread across multiple AZs and at least 4-6 instance types
- Handle the 2-minute warning signal to drain connections and save state
- Use EC2 Instance Rebalance Recommendations for earlier warning signals
Real Spot Pricing: us-east-1
| Instance type | On-demand/hr | Typical Spot/hr | Savings |
|---|---|---|---|
| m7g.xlarge | $0.1632 | ~$0.055 | ~66% |
| m6i.xlarge | $0.1920 | ~$0.065 | ~66% |
| c7g.xlarge | $0.1369 | ~$0.045 | ~67% |
| r7g.xlarge | $0.2128 | ~$0.070 | ~67% |
| t3.xlarge | $0.1664 | ~$0.050 | ~70% |
Spot prices change continuously. These are representative values for general-purpose and compute instances in us-east-1. GPU and specialty instances see wider swings.
When to Use Each: A Decision Framework
Follow this step-by-step:
Step 1: Categorize your workload
- Can it tolerate interruptions? (stateless, checkpointable, batch) —> Consider Spot
- Must it run 24/7 with predictable capacity? —> Consider Savings Plans or RIs
- Does it run on RDS, ElastiCache, or Redshift? —> Reserved Instances (Savings Plans don’t apply)
Step 2: Assess your confidence in the configuration
- Will you keep the same instance family for 1-3 years? —> EC2 Instance Savings Plans or Standard RIs
- Might you change instance types, switch to Graviton, or move regions? —> Compute Savings Plans
- No idea what your usage will look like? —> Start with on-demand, analyze for 2-3 months, then commit
Step 3: Pick the commitment level
- High confidence + want maximum savings —> 3-year, all upfront
- Moderate confidence —> 1-year, no upfront (preserve cash and flexibility)
- Low confidence —> Compute Savings Plans, 1-year, no upfront
Step 4: Layer in Spot
- Identify fault-tolerant workloads: batch processing, CI/CD, dev/test, data pipelines, stateless web tier behind a load balancer
- Start with 20-30% Spot in your Auto Scaling Groups and increase as you build confidence
Combining All Three: The Layered Strategy
The most cost-effective approach uses all three pricing models in layers:
Layer 1: Savings Plans for your baseline (covers 60-70% of compute)
Buy Compute Savings Plans or EC2 Instance Savings Plans to cover your steady-state usage. This is the compute that runs 24/7 regardless of traffic. Size this to your minimum, not your average. It is better to be 5% under-committed than 5% over-committed.
Layer 2: Spot for variable and fault-tolerant workloads (covers 15-25%)
Run batch jobs, CI/CD pipelines, dev environments, data processing, and stateless application tiers on Spot. Use mixed instance type ASGs with capacity-optimized allocation.
Layer 3: On-demand for the rest (covers 10-20%)
Keep on-demand for burst capacity, workloads that cannot tolerate interruption, and anything you haven’t analyzed yet. On-demand is not waste. It is the flexibility buffer.
Layer 4: Reserved Instances for non-EC2 services
Buy RIs for RDS, ElastiCache, OpenSearch, and Redshift. Savings Plans do not cover these services, so RIs are your only commitment option.
Spot for Batch, CI/CD, and Dev Workloads
These are the easiest Spot wins because the workloads are inherently interruptible.
CI/CD Pipelines
CI/CD jobs are short-lived and stateless. If a Spot instance gets reclaimed mid-build, you restart the build. Most CI systems handle this natively.
GitHub Actions self-hosted runners on Spot:
Use an ASG with Spot instances as your runner fleet. Set the ASG to scale based on queue depth. If an instance gets interrupted, the job re-queues automatically.
Batch Processing
AWS Batch has native Spot support. Set your compute environment to use Spot:
aws batch create-compute-environment \
--compute-environment-name my-batch-spot \
--type MANAGED \
--compute-resources type=SPOT,minvCpus=0,maxvCpus=256,\
instanceTypes=m7g.xlarge,m6g.xlarge,c7g.xlarge,c6g.xlarge,\
subnets=subnet-xxx,securityGroupIds=sg-xxx,\
allocationStrategy=SPOT_CAPACITY_OPTIMIZED
Dev/Test Environments
Run dev and test environments on Spot by default. If an instance gets interrupted during development, the developer launches a new one. The 2-minute warning is usually enough to push any uncommitted work.
Graviton + Spot: Maximum Savings Stack
Graviton (ARM-based) instances are 20-25% cheaper than equivalent x86 instances at on-demand prices. Combine that with Spot pricing, and you stack discounts.
Example savings on an m7g.xlarge:
| Pricing model | Hourly cost | vs x86 on-demand |
|---|---|---|
| m6i.xlarge on-demand (x86 baseline) | $0.1920 | 0% |
| m7g.xlarge on-demand (Graviton) | $0.1632 | -15% |
| m7g.xlarge Spot | ~$0.055 | -71% |
That is a 71% reduction from your x86 on-demand baseline by combining architecture migration with Spot pricing.
What runs on Graviton without code changes:
- Containerized workloads (rebuild the image for ARM64, everything else stays the same)
- Java applications (JVM handles the architecture difference)
- Python, Node.js, Go, Rust, Ruby, PHP applications
- Most Linux-based workloads
What needs work:
- Applications with x86-specific compiled dependencies or native libraries
- Windows workloads (Graviton runs Linux only)
- Workloads dependent on x86 AMIs that have no ARM64 equivalent
If you are already running containers, the Graviton migration is straightforward. Multi-architecture Docker builds let you support both x86 and ARM64 from the same Dockerfile, making rollback easy.
Common Mistakes
1. Over-Committing on Savings Plans
The most expensive mistake. Teams look at their current spend, buy Savings Plans to cover 100% of it, and then usage drops. You pay for the commitment whether you use it or not.
Fix: Commit to 70-80% of your steady minimum usage. Use on-demand and Spot for the rest.
2. Ignoring RI and Savings Plan Expirations
Commitments expire silently. One day your effective rate jumps 40-60% because a 3-year RI expired and nobody renewed it. This shows up as a cost anomaly weeks later when someone checks the bill.
Check upcoming expirations:
aws ce get-reservation-purchase-recommendation \
--service "Amazon Elastic Compute Cloud - Compute" \
--lookback-period-in-days SIXTY_DAYS \
--term-in-years ONE_YEAR \
--payment-option NO_UPFRONT
List your active Savings Plans and their expiration dates:
aws savingsplans describe-savings-plans \
--query 'SavingsPlans[?state==`active`].{Id:savingsPlanId,Type:savingsPlanType,Commitment:commitment,End:end}' \
--output table
3. Wrong RI Scope
Buying zonal RIs when you should have bought regional. Zonal RIs lock the discount to a single AZ. If your ASG shifts traffic to a different AZ, the discount does not follow. Regional RIs are almost always the better default.
4. Buying Standard RIs Instead of Savings Plans
Standard RIs and EC2 Instance Savings Plans offer similar discounts. But Savings Plans are simpler to manage, auto-apply to your usage, and don’t require you to deal with the RI Marketplace. Unless you need the capacity reservation that comes with zonal RIs, EC2 Instance Savings Plans are the better choice.
5. Running Spot Without Diversification
Using a single instance type for Spot is asking for interruptions. When AWS reclaims capacity, it often affects an entire instance type in an AZ at once. Spread across at least 4-6 instance types and multiple AZs.
6. Not Using Capacity-Optimized Allocation
The default Spot allocation strategy is lowest-price. This sounds good but picks instance pools most likely to be interrupted. Switch to capacity-optimized, which selects pools with the most available capacity, reducing interruption rates significantly.
How to Check Your Current Coverage
Before making any commitment purchases, audit what you have.
Reserved Instance Coverage
aws ce get-reservation-coverage \
--time-period Start=$(date -u -d '30 days ago' +%Y-%m-%d),End=$(date -u +%Y-%m-%d) \
--granularity MONTHLY \
--query 'CoveragesByTime[].{Period:TimePeriod.Start,Hours:Total.CoverageHours.CoverageHoursPercentage}'
Reserved Instance Utilization
aws ce get-reservation-utilization \
--time-period Start=$(date -u -d '30 days ago' +%Y-%m-%d),End=$(date -u +%Y-%m-%d) \
--granularity MONTHLY \
--query 'UtilizationsByTime[].{Period:TimePeriod.Start,Utilization:Total.UtilizationPercentage}'
Spot Usage as Percentage of Total
aws ce get-cost-and-usage \
--time-period Start=$(date -u -d '30 days ago' +%Y-%m-%d),End=$(date -u +%Y-%m-%d) \
--granularity MONTHLY \
--metrics UnblendedCost \
--group-by Type=DIMENSION,Key=PURCHASE_TYPE \
--query 'ResultsByTime[].Groups[].{Type:Keys[0],Cost:Metrics.UnblendedCost.Amount}'
This shows your spend broken down by On-Demand, Reserved, Savings Plans, and Spot. If Spot is less than 10% and you have fault-tolerant workloads, there is room to save.
Real-World Example: Optimizing a $10K/Month Account
Here is a realistic scenario. A mid-size SaaS company running $10,000/month in EC2 on-demand.
Current state:
- 6x m6i.xlarge running 24/7 (web tier): $1,152/month each, $6,912 total
- 2x c6i.xlarge for batch processing: $1,152/month each, runs ~60% of the time, ~$1,382 total
- Misc on-demand (dev, test, one-off jobs): ~$1,706/month
- Total: ~$10,000/month
Step 1: Migrate to Graviton where possible
Move the web tier from m6i.xlarge ($0.192/hr) to m7g.xlarge ($0.1632/hr). Immediate 15% savings on those instances.
- Web tier drops from $6,912 to $5,875/month
- Savings: $1,037/month
Step 2: Buy Compute Savings Plans for the baseline
The web tier runs 24/7. Commit to covering 5 of the 6 instances (keep buffer). At a 1-year no-upfront Compute Savings Plan rate, that is roughly 38% off.
- 5x m7g.xlarge covered: drops from $4,896 to ~$3,036/month
- Savings: $1,860/month
Step 3: Move batch processing to Spot
Batch jobs on c7g.xlarge Spot at ~67% discount. Diversify across c7g, m7g, c6g, and m6g instance types.
- Batch drops from $1,382 to ~$456/month
- Savings: $926/month
Step 4: Move dev/test to Spot
Run dev and test environments on Spot instances.
- Dev/test drops from $1,706 to ~$580/month
- Savings: $1,126/month
Result:
| Category | Before | After | Savings |
|---|---|---|---|
| Web tier (Graviton + SP) | $6,912 | $3,911 | $3,001 |
| Batch (Graviton + Spot) | $1,382 | $456 | $926 |
| Dev/test (Spot) | $1,706 | $580 | $1,126 |
| Total | $10,000 | $4,947 | $5,053 (50%) |
From $10,000/month to under $5,000/month. No architectural changes. No application rewrites. Just smarter purchasing.
Over 12 months, that is $60,636 saved. Over 3 years with a 3-year Savings Plan instead of 1-year, the web tier savings deepen further, pushing total savings closer to 60%.
Automate the Analysis
Manually tracking RI expirations, Savings Plan utilization, and Spot coverage across multiple accounts gets tedious fast. This is exactly the kind of analysis that should be automated.
CostPatrol scans your AWS accounts and flags optimization opportunities like these automatically. It detects under-utilized Reserved Instances, expired commitments, workloads running on-demand that should be on Spot, and instances that could benefit from Graviton migration. Instead of running CLI commands manually, you get actionable findings with estimated savings.
Summary
The three pricing models are not competitors. They are layers.
- Savings Plans cover your predictable baseline. Start with Compute Savings Plans unless you are certain your instance family and region won’t change.
- Reserved Instances cover non-EC2 services (RDS, ElastiCache, Redshift, OpenSearch) where Savings Plans do not apply.
- Spot Instances cover everything that can tolerate interruption: batch, CI/CD, dev/test, stateless tiers.
- On-demand fills the gaps and handles burst capacity.
Commit conservatively. Diversify your Spot pools. Check your utilization before buying more. And automate the monitoring so expired commitments and missed Spot opportunities do not slip through the cracks.