AWS Reserved Instances (RIs) and Savings Plans are the single largest levers for reducing EC2 costs in production AWS environments — offering 30-50% discounts for committing to capacity. Most companies either don't use them (paying full on-demand pricing), or mismanage them (buying commitments for instance types that later get replaced or scaled down). The difference between a good RI strategy and a bad one can be hundreds of thousands of dollars annually at scale.
Reserved Instances vs. Savings Plans: Which to Use
Reserved Instances (RIs): Committed to a specific instance type (e.g., m5.xlarge) in a specific region, for 1 or 3 years. Discounts up to 60% vs. on-demand. More complex to manage but maximum discount for specific predictable workloads.
Compute Savings Plans: More flexible commitment — you commit to a dollar amount of compute per hour, applicable across any instance type, family, size, or region. Lower discount (up to 66% for 3-year) but flexible against instance family changes.
EC2 Instance Savings Plans: Commitment to a specific instance family in a region (e.g., m5 in us-east-1) regardless of size. Intermediate flexibility and discount.
Recommendation for most teams: Savings Plans for baseline capacity, with targeted RIs only for stable workloads with known long-term instance types. The flexibility of Savings Plans handles the reality that instance families and sizes change over time.
Step 1: Coverage Analysis Before Buying Anything
Never buy commitments without a coverage baseline. You need to understand: - What is your current on-demand usage by instance type and region? - What percentage of your compute hours are already covered by existing commitments? - What's the stable baseline vs. variable peak?
import boto3
from datetime import datetime, timedelta
ce = boto3.client("ce", region_name="us-east-1")
def get_coverage_report(days: int = 30) -> dict:
"""Get current RI coverage across EC2."""
end = datetime.today().strftime("%Y-%m-%d")
start = (datetime.today() - timedelta(days=days)).strftime("%Y-%m-%d")
response = ce.get_reservation_coverage(
TimePeriod={"Start": start, "End": end},
Granularity="MONTHLY",
GroupBy=[{"Type": "DIMENSION", "Key": "INSTANCE_TYPE"}],
Metrics=["CoverageHours"],
)
coverage_by_type = {}
for group in response["Total"].get("CoveragesByGroup", []):
instance_type = group["Attributes"]["INSTANCE_TYPE"]
coverage = group["Coverage"]["CoverageHours"]["CoverageHoursPercentage"]
coverage_by_type[instance_type] = float(coverage)
return coverage_by_type
Target 70-80% coverage for stable workloads. Going above 80% risks overcommitment — if you scale down or change instance types, you're paying for coverage you can't use.
Step 2: Identify Your Stable Baseline
Your RI commitment should cover your steady-state base load, not your peak. The difference:
On-demand hours (30 days): 10,000 hours
Minimum concurrent instances: 8
Maximum concurrent instances: 25
Stable baseline = 8 instances × 24 hours × 30 days = 5,760 hours
Variable capacity = remaining 4,240 hours
RI commitment target: ~5,000 hours (slightly under stable baseline)
Variable capacity: on-demand or Spot Instances
Cover the baseline with commitments; handle variable capacity with on-demand or Spot. This is the core RI strategy logic.
Tools for this analysis: AWS Cost Explorer's "Savings Plans recommendations" and "RI recommendations" tabs do this calculation automatically. Review the recommendations, but don't blindly accept them — they optimize for maximum discount, not for your actual usage patterns and flexibility needs.
Step 3: Payment Options and Their ROI
For each RI or Savings Plan, you choose a payment option:
| Option | Upfront | Discount vs. On-Demand | |--------|---------|----------------------| | No Upfront (1yr) | $0 | ~30% | | Partial Upfront (1yr) | 50% | ~35% | | All Upfront (1yr) | 100% | ~37% | | No Upfront (3yr) | $0 | ~45% | | All Upfront (3yr) | 100% | ~60% |
ROI calculation for All Upfront 3-year:
If you're spending $10,000/month on a stable EC2 workload: - All Upfront 3-year commitment: pay ~$21,600 upfront for $10,000/month of compute - Total on-demand over 3 years: $360,000 - Savings: $338,400 over 3 years
The discount is real and substantial — the question is whether you're confident enough in the workload's 3-year stability to make that bet. Most companies use 1-year commitments with partial upfront for the balance of flexibility and discount.
Step 4: Instance Flexibility Matters
When buying Standard RIs, understand instance size flexibility:
- RIs within the same instance family are size-flexible within a region (e.g., an m5.xlarge RI can cover two m5.large instances, or half of an m5.2xlarge)
- This is a significant benefit — it means you're not locked into a specific size, just a family
- Convertible RIs go further — you can exchange for a different instance type within the same or higher tier (useful when instance families change)
Don't buy RIs for instance types that are likely to be replaced. If you're still on m4 instances, buy a Compute Savings Plan rather than m4 RIs — cover the transition to m5 or m6i without wasting commitments.
Step 5: Portfolio Management
RI portfolios need ongoing management: - Monthly reviews: Are coverages still accurate? Did your workload change? - Utilization monitoring: Low-utilization RIs indicate overcommitment or workload changes - RI Marketplace: Unused RIs can be listed for sale on the AWS Reserved Instance Marketplace, partially recovering costs from overcommitments - Modification: Standard RIs can be modified (instance size, within same family) — useful for gradual scaling changes
def get_utilization_report(days: int = 30) -> list[dict]:
"""Identify underutilized reservations."""
end = datetime.today().strftime("%Y-%m-%d")
start = (datetime.today() - timedelta(days=days)).strftime("%Y-%m-%d")
response = ce.get_reservation_utilization(
TimePeriod={"Start": start, "End": end},
Granularity="MONTHLY",
GroupBy=[{"Type": "DIMENSION", "Key": "SUBSCRIPTION_ID"}],
)
underutilized = []
for group in response.get("UtilizationsByTime", [{}])[0].get("Groups", []):
utilization = float(group["Utilization"]["UtilizationPercentage"])
if utilization < 80: # Flag anything under 80% utilization
underutilized.append({
"subscription_id": group["Attributes"]["SUBSCRIPTION_ID"],
"utilization": utilization,
})
return underutilized
Flag and investigate any reservation with <80% utilization. Options: modify the RI, sell on Marketplace, or retire the workload.
Typical Results
On a $50,000/month AWS EC2 bill with no existing commitments, a methodical RI strategy typically produces: - First 60 days: analysis and first commitment purchases - Month 3-6: 25-35% EC2 cost reduction ($12,500-$17,500/month savings) - Mature state (12+ months): 35-50% reduction from on-demand ($17,500-$25,000/month savings)
The investment: 1-2 weeks of engineering and finance time, plus ongoing monthly 1-hour review.
Rutagon Helps You Build Your RI Strategy
If your AWS EC2 spend feels higher than it should be, Rutagon analyzes your current usage, models commitment scenarios, and manages the RI purchase and portfolio process. Talk to us at rutagon.com/contact.
See also: AWS cost monitoring setup and FinOps capabilities.
FAQ
What's the difference between Reserved Instances and Savings Plans in simple terms?
Reserved Instances: commit to a specific instance type in a specific region for 1-3 years. Less flexible, maximum discount. Savings Plans: commit to a dollar amount of compute per hour, usable against any instance type. More flexible, slightly lower discount. For most teams, Savings Plans are the right choice because workloads and instance types change over time.
Can I use RIs for containers (ECS, EKS)?
Compute Savings Plans apply to EC2 instances running ECS/EKS workloads. If you're running ECS Fargate, Fargate-specific Compute Savings Plans apply. EKS node groups are EC2 instances, so standard EC2 Savings Plans coverage applies. EKS Fargate is covered by Fargate Savings Plans.
How do I handle commitment risk during a potential scale-down?
Buy commitments at 70% of current stable baseline rather than 100% — this provides buffer for a 30% scale-down before your coverage exceeds your actual usage. For workloads with high scale-down risk (pre-revenue products, experimental services), use Compute Savings Plans (no-upfront) rather than RIs to minimize committed capital while still capturing some discount.
Do Reserved Instances work for spot instance capacity?
No — Reserved Instances apply to on-demand instances, not Spot instances. However, a common cost optimization architecture uses RIs for baseline capacity and Spot Instances for variable peak capacity — combining the benefits of both pricing models.
How long does it take to see RI savings reflected in the AWS bill?
Savings begin immediately upon activation of the RI or Savings Plan. The credit appears on your next monthly bill — you'll see the on-demand charge replaced by the RI rate for covered usage. AWS Cost Explorer shows coverage and utilization data that confirms your commitments are being applied.