EC2 Auto Scaling Policies Explained: Target Tracking, Step, Scheduled & Predictive
EC2 Auto Scaling policies tell your Auto Scaling Group when to add instances and when to remove them. Without policies, your ASG stays at a fixed desired capacity. It replaces failed instances but does not respond to changes in load. Scaling policies are what make your infrastructure elastic.
A well-configured scaling policy keeps your application performant during traffic spikes without paying for idle capacity the rest of the time. That balance (responsive enough to handle load, conservative enough not to waste money) is what the different policy types help you achieve.
For most teams, the right approach is straightforward: start with target tracking, add scheduled scaling if your traffic patterns are predictable, and consider predictive scaling once you have enough history. Step scaling is available when you need finer control, but most workloads do not need it.
How to think about scaling policies
Imagine your web application is a coffee shop. At 9am it fills up. At 3pm it quiets down. On Monday morning you have a promotion and you know it will be packed.
Scaling policies decide how many staff (instances) to have on at any given time:
- Target tracking: “keep the queue at 10 people per server.” AWS watches the queue and hires or releases staff automatically to maintain that ratio.
- Step scaling: “if the queue is 20-40 people, add 1 server; if over 40, add 3.” More explicit rules, more manual control.
- Scheduled scaling: “at 8am every weekday, bring in 5 extra staff.” You know the rush is coming, so you prepare before it arrives.
- Predictive scaling: AWS looks at the last two weeks of traffic history, predicts when it will get busy, and brings staff in before that happens.
- Simple scaling: the original version of step scaling. Slower and less flexible. Avoid for any new setup.
Why EC2 Auto Scaling policies matter
An Auto Scaling Group alone does not scale your application. It simply maintains a fixed desired capacity and replaces unhealthy instances. Scaling policies are what connect your infrastructure to real demand.
Without scaling policies you face a constant trade-off: provision for peak load (expensive, mostly idle) or provision for average load (cheap but unreliable during spikes). Scaling policies let you start small, grow when needed, and shrink when load drops automatically.
Done well, scaling policies reduce your EC2 bill substantially and remove the need to manually watch dashboards and resize your fleet. When combined with Spot Instances in a mixed-instance ASG, automated scaling can cut compute costs by 60-90% compared to a fixed fleet of On-Demand instances.
How EC2 Auto Scaling decides when to add or remove instances
EC2 Auto Scaling uses CloudWatch metrics as the signal for when to scale. The most common signals are CPU utilisation, network throughput, and request rate per instance in a load balancer target group.
When a metric crosses a threshold, a CloudWatch alarm fires. Depending on the policy type, that alarm either triggers an immediate scaling action (step scaling) or AWS evaluates whether current capacity still matches the desired target (target tracking). The result is a change to the ASG’s desired capacity: the number of healthy instances AWS tries to maintain at any given moment.
Once desired capacity changes, AWS launches or terminates instances to reach that number. New instances use the configuration from a launch template, start up, pass health checks, and register with the load balancer before handling traffic.
There are two broad categories of scaling behaviour:
- Dynamic scaling: reacts to live metrics in real time. Includes target tracking, step scaling, and simple scaling.
- Proactive scaling: scales based on a schedule or predictions, before demand arrives. Includes scheduled scaling and predictive scaling.
Most production setups combine both: dynamic scaling for real-time responsiveness, and scheduled or predictive scaling to avoid the lag of reacting to a traffic surge you already anticipated.
Policy types at a glance
| Policy type | Complexity | Best for | Response style | Alarms | Key drawback |
|---|---|---|---|---|---|
| Target tracking | Low | Most workloads | Continuous, reactive | Automatic | Less control over scaling increments |
| Step scaling | Medium | Explicit thresholds with tiered response | Reactive, tiered | Manual | More setup; alarms must be created and managed |
| Simple scaling | Low | Legacy only | Reactive, fixed | Manual | Blocks during cooldown; misses continued load growth |
| Scheduled scaling | Low | Predictable traffic patterns | Time-based, proactive | None (time-based) | Cannot react to unexpected spikes |
| Predictive scaling | Medium | Recurring cyclical patterns | Forecast-based, proactive | Automatic | Needs 14+ days of history; can mispredict |
Target tracking scaling
Target tracking is the default choice for most workloads. You define a metric and a target value (for example, keep average CPU utilisation at 50%) and AWS continuously adjusts the ASG desired capacity to maintain that target. You do not create or manage CloudWatch alarms yourself. AWS handles that automatically.
Target tracking scales out fast when the metric rises above the target and scales in conservatively when it drops. AWS builds in hysteresis to prevent oscillation. It will not immediately scale back in after a brief dip below the target.
Create a target tracking policy for CPU utilisation:
aws autoscaling put-scaling-policy \
--auto-scaling-group-name production-web-asg \
--policy-name cpu-target-tracking \
--policy-type TargetTrackingScaling \
--target-tracking-configuration '{
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ASGAverageCPUUtilization"
},
"TargetValue": 50.0,
"ScaleInCooldown": 300,
"ScaleOutCooldown": 60,
"EstimatedInstanceWarmup": 120
}'A scale-out cooldown of 60 seconds lets AWS respond quickly to load spikes. A scale-in cooldown of 300 seconds prevents premature removal of instances when load briefly dips below the target.
Predefined metrics for target tracking
AWS provides four predefined metrics for target tracking policies:
ASGAverageCPUUtilization: average CPU across all instances in the ASGASGAverageNetworkIn: average inbound network bytes per instance per minuteASGAverageNetworkOut: average outbound network bytes per instance per minuteALBRequestCountPerTarget: requests per second per registered target in an Application Load Balancer target group
For web applications behind a load balancer, use ALBRequestCountPerTarget rather than CPU. It measures actual request load directly. Set a target of 500-1000 requests per instance per minute and AWS scales your ASG to maintain that rate as traffic rises and falls. CPU is a reasonable fallback if you are not behind an ALB, but it is a proxy metric and can lag behind actual load.
Custom metrics
You can use any CloudWatch metric as a target tracking source, including custom metrics your application publishes. A common pattern for queue workers is using SQS queue depth: set a target of 100 messages per worker and AWS scales the fleet to maintain that depth.
Target tracking automatically creates and manages CloudWatch alarms on your behalf. Do not modify or delete these alarms manually. AWS regenerates them and your changes will be overwritten.
Step scaling
Step scaling gives you explicit control over how many instances to add or remove depending on how far a metric has exceeded a threshold. You define a set of steps, where each step specifies a metric interval and a scaling adjustment.
For example, a CPU-based step policy might say:
- CPU 60-70%: add 1 instance
- CPU 70-90%: add 2 instances
- CPU 90%+: add 4 instances
Unlike target tracking, step scaling requires you to create CloudWatch alarms manually and link them to the policy. Create the scaling policy first to get its ARN, then attach that ARN to the alarm:
# Step 1: Create the step scaling policy — capture the PolicyARN it returns
POLICY_ARN=$(aws autoscaling put-scaling-policy \
--auto-scaling-group-name production-web-asg \
--policy-name cpu-step-scale-out \
--policy-type StepScaling \
--adjustment-type ChangeInCapacity \
--metric-aggregation-type Average \
--estimated-instance-warmup 120 \
--step-adjustments '[
{"MetricIntervalLowerBound": 0, "MetricIntervalUpperBound": 10, "ScalingAdjustment": 1},
{"MetricIntervalLowerBound": 10, "MetricIntervalUpperBound": 30, "ScalingAdjustment": 2},
{"MetricIntervalLowerBound": 30, "ScalingAdjustment": 4}
]' --query PolicyARN --output text)
# Step 2: Create the CloudWatch alarm and attach the policy ARN as the alarm action
aws cloudwatch put-metric-alarm \
--alarm-name high-cpu-alarm \
--metric-name CPUUtilization \
--namespace AWS/EC2 \
--dimensions Name=AutoScalingGroupName,Value=production-web-asg \
--statistic Average \
--period 60 \
--evaluation-periods 3 \
--threshold 60 \
--comparison-operator GreaterThanOrEqualToThreshold \
--alarm-actions "$POLICY_ARN"The MetricIntervalLowerBound values are offsets relative to the alarm threshold (60%). So:
- 60-70% (threshold + 0 to 10): add 1 instance
- 70-90% (threshold + 10 to 30): add 2 instances
- 90%+ (threshold + 30): add 4 instances
The policy above only handles scaling out. You must create a separate scale-in policy with its own CloudWatch alarm (triggering when CPU drops below your threshold) if you want instances to be removed when load drops. This is one reason many teams prefer target tracking, which handles both directions automatically.
Use step scaling when target tracking does not give you fine enough control. For example, a queue worker fleet where a backlog of 10,000 messages needs a meaningfully different response than a backlog of 100.
Simple scaling (legacy)
Simple scaling is the original Auto Scaling policy type. When a CloudWatch alarm triggers, the ASG adjusts by a fixed amount, and then all scaling is blocked for the entire cooldown period regardless of what the metric does during that time.
This is the core weakness: if load continues climbing during a cooldown, the policy cannot respond. Step scaling does everything simple scaling does but responds continuously to load rather than waiting for the cooldown to expire. There is no reason to use simple scaling for new policies.
Scheduled scaling
Scheduled scaling changes the ASG min, max, or desired capacity at a specific time, either once or on a recurring schedule. It is a proactive approach: you pre-scale before anticipated demand rather than reacting after it arrives.
Common use cases:
- Scale up to 20 instances every weekday morning before business hours start
- Scale down to 2 instances overnight and on weekends
- Pre-scale for a product launch or marketing campaign at a fixed time
# Scale up every weekday at 8am UTC
aws autoscaling put-scheduled-update-group-action \
--auto-scaling-group-name production-web-asg \
--scheduled-action-name scale-up-for-business-hours \
--min-size 5 \
--desired-capacity 10 \
--recurrence "0 8 * * 1-5"
# Scale down every night at 8pm UTC
aws autoscaling put-scheduled-update-group-action \
--auto-scaling-group-name production-web-asg \
--scheduled-action-name scale-down-overnight \
--min-size 2 \
--desired-capacity 2 \
--recurrence "0 20 * * *"The —recurrence parameter uses cron syntax. Scheduled actions run in UTC by default. If your traffic follows a local business schedule, either convert your times to UTC manually or use the —time-zone flag:
aws autoscaling put-scheduled-update-group-action \
--auto-scaling-group-name production-web-asg \
--scheduled-action-name scale-up-eastern \
--desired-capacity 10 \
--recurrence "0 8 * * 1-5" \
--time-zone "America/New_York"Scheduled scaling works well alongside target tracking. Use scheduled scaling to pre-scale before a predictable surge (so you are not waiting for metrics to react to a traffic increase you already knew was coming), and target tracking to fine-tune capacity in response to actual load within that range.
Predictive scaling
Predictive scaling uses machine learning to forecast future demand based on historical patterns, then pre-scales your ASG before that demand arrives. Unlike scheduled scaling (where you define the schedule manually), predictive scaling learns your traffic pattern automatically from at least 14 days of CloudWatch metric history.
It is most useful for applications with strong cyclical patterns: daily peaks, weekly rhythms, or seasonal spikes. Predictive scaling works alongside dynamic scaling policies. It handles the proactive pre-scaling while target tracking handles real-time adjustments.
Predictive scaling has two operating modes:
- ForecastOnly: generates and stores forecasts but does not act on them. Use this first to review the predicted capacity before enabling automated scaling.
- ForecastAndScale: acts on the forecast automatically, scaling out before the predicted traffic increase.
aws autoscaling put-scaling-policy \
--auto-scaling-group-name production-web-asg \
--policy-name predictive-cpu-policy \
--policy-type PredictiveScaling \
--predictive-scaling-configuration '{
"MetricSpecifications": [
{
"TargetValue": 50,
"PredefinedMetricPairSpecification": {
"PredefinedMetricType": "ASGCPUUtilization"
}
}
],
"Mode": "ForecastAndScale",
"SchedulingBufferTime": 300
}'SchedulingBufferTime of 300 seconds tells AWS to pre-scale 5 minutes before the forecasted traffic increase. This buffer gives new instances time to initialise and pass health checks before the peak arrives. For applications with slow startup times, increase this value.
Predictive scaling needs at least 14 days of CloudWatch metric history to generate useful forecasts. Start in ForecastOnly mode, review the predicted capacity graphs in the EC2 Auto Scaling console, and switch to ForecastAndScale once you are confident the forecast reflects your real traffic patterns.
Cooldown versus instance warmup
These two concepts are often confused, but they serve distinct purposes.
Cooldown is a pause that applies after a scaling activity. During a cooldown, the ASG will not take any further scaling action. Any alarms that fire are suspended until the cooldown expires. Cooldown applies to simple scaling and to the ASG-level default cooldown setting. The default is 300 seconds (5 minutes).
Instance warmup is different. It applies to target tracking and step scaling and controls when a newly launched instance’s metrics are included in scaling calculations. If your application takes two minutes to initialise, a warmup period of 120 seconds tells AWS not to factor that instance’s early (low) CPU into the ASG average. Without warmup, AWS might see artificially low average CPU immediately after scaling out and scale back in before the new instances are even ready.
Set EstimatedInstanceWarmup to match how long your application actually takes to start handling traffic. This is often longer than the EC2 instance boot time. An instance might be running in 30 seconds, but your application could take another 90 seconds to initialise and pass load balancer health checks.
Set EstimatedInstanceWarmup to your application’s actual start-up time (not EC2 boot time). Set ScaleOutCooldown short (60 seconds) so AWS responds to load fast. Set ScaleInCooldown long (300+ seconds) so you do not remove instances that were just added. Choose an instance type with fast boot times if your workload demands rapid scale-out.
How to choose the right scaling approach
Not sure where to start? Use this order: (1) Target tracking for almost everything. (2) Add scheduled scaling if your traffic follows a predictable clock (business hours, weekly spikes). (3) Enable predictive scaling once you have 14+ days of history and want AWS to automate the pre-scaling. (4) Switch to step scaling only if you need explicit control over how much capacity to add at different load thresholds.
Start with target tracking for most workloads
Target tracking covers the majority of real-world scenarios with minimal configuration. Use ASGAverageCPUUtilization at 50-60% for general-purpose web and API backends. For applications behind an Application Load Balancer, prefer ALBRequestCountPerTarget: it reflects actual request load more directly than CPU and handles uneven traffic distribution better.
Add scheduled scaling for predictable peaks
If your traffic follows a consistent pattern (business hours, weekly spikes, known marketing events), add scheduled scaling to pre-scale before those windows. This eliminates the lag of waiting for metrics to respond to a surge you already anticipated. A B2B SaaS product with strong 9-to-5 weekday usage is a textbook case.
Use predictive scaling for recurring cyclical patterns
If you have at least two weeks of traffic history and your patterns repeat reliably, predictive scaling can automate what you would otherwise do with scheduled actions. It is a good fit for consumer apps with strong daily usage patterns. Always start in ForecastOnly mode and validate the forecast before switching to ForecastAndScale.
Reserve step scaling for explicit tiered responses
Step scaling is the right tool when different load levels genuinely require different-magnitude responses. For example, a queue worker fleet that needs 2 extra instances at mild backlog but 20 at severe backlog. It is more work to configure and maintain. Do not use it just because it offers more options.
Treat simple scaling as legacy
Simple scaling is functionally replaced by step scaling. If you need the alarm-and-action pattern, use step scaling instead.
Combine approaches for production workloads
Proactive and dynamic scaling are complementary, not competing. A typical production setup uses scheduled scaling to pre-scale before known peaks, target tracking to maintain a target metric under variable load, and a generous scale-in cooldown to prevent thrashing. When multiple dynamic policies are active simultaneously, AWS always takes the action that results in the largest number of instances, so policies cooperate rather than conflict.
For cost efficiency, consider pairing your ASG with a mix of On-Demand and Spot Instances to reduce the cost of scale-out capacity significantly.
Common mistakes
- Setting the CPU target too high. A target of 80-90% leaves almost no headroom. When a spike arrives, the existing instances are near their limit and new instances cannot come online in time. Start at 50-60% to give the ASG room to respond before the current fleet is overwhelmed.
- Not configuring instance warmup. Without a warmup period, a newly launched instance with low startup CPU can cause AWS to scale back in before that instance is even serving traffic. Set
EstimatedInstanceWarmupto match your application’s actual initialisation time. - Using simple scaling for new policies. Simple scaling blocks during the cooldown period and cannot respond to load that continues growing. Use step scaling instead. It is a strict improvement.
- Not combining scheduled and dynamic scaling. If you know traffic increases every morning and rely on target tracking alone, your ASG will always be catching up to demand instead of ready for it. Use scheduled or predictive scaling to pre-scale before predictable surges.
- Scaling in too aggressively. A short scale-in cooldown (under 5 minutes) often causes a rapid cycle of scaling out and back in. Keep scale-in conservative: 5-10 minutes minimum. The rule is: scale out fast, scale in slowly.
- Not testing under realistic load. Scaling policies behave differently under real load than in theory. Run a load test, watch how your ASG responds, and verify that new instances register with the load balancer and pass health checks before traffic is routed to them.
Summary
- Target tracking is the simplest and most commonly used policy. Set a target metric value and AWS handles alarms and scaling decisions automatically. Start here.
- Step scaling requires manual alarm creation but offers explicit control over how much capacity to add at different load levels. Use it when target tracking is not precise enough.
- Simple scaling is legacy. Use step scaling instead for any new alarm-based policy.
- Scheduled scaling adjusts capacity on a time-based schedule. Cron expressions default to UTC. Use
—time-zonefor local business hours. - Predictive scaling uses ML forecasting to pre-scale based on 14+ days of history. Start in
ForecastOnlymode before enabling automated scaling. - Cooldown blocks all scaling after an event. Instance warmup delays metric inclusion for newly launched instances. Set it to match your application’s actual initialisation time, not just EC2 boot time.
- For most production setups: combine target tracking with scheduled scaling, scale out fast, scale in slowly.
Frequently asked questions
Which EC2 Auto Scaling policy should I use first?
Start with target tracking. Set a target metric (50% average CPU utilisation is a good starting point) and AWS automatically manages CloudWatch alarms and scaling decisions. It requires the least configuration and works well for most web and API workloads.
What is the difference between target tracking and step scaling?
Target tracking lets AWS manage the alarms and decisions: you set a target value and AWS scales to maintain it. Step scaling requires you to create CloudWatch alarms manually and define different scaling increments for different severity levels. Use target tracking by default; switch to step scaling only when you need explicit control over the scaling response at different load thresholds.
Can I combine scheduled scaling with target tracking?
Yes, and this is a common pattern. Use scheduled scaling to pre-scale your ASG before a predictable traffic window (such as weekday mornings), and target tracking to fine-tune capacity in response to actual load. When both policies are active, AWS always takes the action that results in the largest number of instances.
Does predictive scaling replace dynamic scaling?
No. Predictive scaling pre-scales instances based on historical forecasts but does not react to live metric deviations. Dynamic scaling (target tracking or step scaling) continues to handle real-time adjustments. Use both together for workloads with cyclical patterns.
What is the difference between cooldown and instance warmup?
Cooldown is a fixed pause after a scaling activity during which no further scaling can happen. It applies to simple scaling and the ASG default. Instance warmup is different: it tells AWS how long to wait before including new instance metrics in scaling calculations, preventing premature scale-in while the instance initialises. Set EstimatedInstanceWarmup to match how long your application takes to start serving traffic.