- Why rightsizing tools miss it
- The evidence that a floor is too high
- Absent metrics are not evidence
- Reading a group that never scaled
- Why we report this finding at zero dollars
- Lowering a floor safely
- Frequently asked questions
Every rightsizing tool will tell you the instance type behind your Auto Scaling group is too big. None of them will ask the more valuable question: how many instances is the group running at three in the morning, and why?
That number is MinSize. It is the floor the group can never go below, which means it is the capacity you pay for around the clock regardless of demand. On a group whose scaling policy has never actually fired, the floor is not part of the bill. It is the bill.
Why rightsizing tools miss it
AWS Compute Optimizer analyses Auto Scaling groups and returns recommendations for them. Those recommendations are about the instance type: this group runs m5.xlarge, the utilization suggests m5.large would do. That is genuinely useful and it is not what this page is about.
The floor is a different question, and it is structurally invisible to that analysis. Compute Optimizer looks at how hard each instance is working. A group of six instances at 65% CPU looks healthy by that measure. The instances are not over-provisioned. There are simply six of them, permanently, because someone set MinSize to 6 during a launch two years ago and nothing has revisited it.
Utilization analysis asks whether each box is the right size. It cannot ask whether you need this many boxes, because from inside the instance the answer always looks like yes.
The savings from lowering a floor are also usually larger than a type change, and carry less risk. Dropping one instance from a six-instance floor removes a sixth of the group's compute cost. There is no rebuild, no AMI change, no restart of anything, and the change reverses in a single API call the moment you dislike it.
The evidence that a floor is too high
There is one CloudWatch metric that answers this directly: GroupInServiceInstances in the AWS/AutoScaling namespace. It records how many instances the group actually had in service, over time.
The test is simple. If the maximum of that metric across the whole observation window equals MinSize, the scaling policy has never fired. The group has been sitting on its floor the entire time. Whatever demand the policy was written to absorb has not arrived, and every instance in that floor has been paid for continuously without ever being requested by load.
aws cloudwatch get-metric-statistics \
--namespace AWS/AutoScaling \
--metric-name GroupInServiceInstances \
--dimensions Name=AutoScalingGroupName,Value=my-app-asg \
--start-time 2026-06-11T00:00:00Z \
--end-time 2026-09-09T00:00:00Z \
--period 3600 --statistics Maximum \
--region ap-south-1
Compare the highest value returned against the group's MinSize:
aws autoscaling describe-auto-scaling-groups \
--auto-scaling-group-names my-app-asg \
--region ap-south-1 \
--query 'AutoScalingGroups[].{Min:MinSize,Desired:DesiredCapacity,Max:MaxSize}'
Absent metrics are not evidence
Here is the trap, and it is the reason a naive version of this check invents findings that are not real.
Auto Scaling group metrics are opt-in per group. Unless somebody ran enable-metrics-collection on that specific group, GroupInServiceInstances does not exist for it. The query above returns an empty result set.
An empty result looks exactly like a quiet group. Both come back with no datapoints above the floor. If a tool treats "no data" as "capacity never rose", it will confidently report that your scaling policy has never fired on a group it has no information about whatsoever. That is a fabricated finding, and it is fabricated in the most damaging possible direction, because it sounds specific.
The correct behaviour is to report the gap rather than guess across it. Our analyzer counts the groups with no metric series and says so in the report, separately from any finding. Group metrics cost nothing, so the fix is free:
aws autoscaling enable-metrics-collection \
--auto-scaling-group-name my-app-asg \
--granularity 1Minute \
--region ap-south-1
The same principle governs how long a window has to be before it means anything. A week of flat capacity proves very little, since weekly batch jobs and month-end reporting both hide inside seven days. We treat 7 and 15 day windows as observations that are structurally incapable of producing an instruction, and require 30 days with at least 80% of the window actually carrying data before a claim is made. The reasoning is set out in the cost optimization guide.
Reading a group that never scaled
A floor that has never been exercised means one of four things, and they call for different responses.
The floor is genuinely oversized. Someone picked a number at creation, load never justified it, and nothing revisited it. This is the common case and it is the one worth money.
The floor encodes availability, not capacity. A floor of 2 or 3 spread across Availability Zones is often there so that losing a zone does not lose the service. That is a deliberate purchase of resilience and lowering it is a real reduction in fault tolerance, not a free saving.
The scaling policy is broken. A policy that has never fired may be misconfigured rather than unneeded, watching a metric that does not move or with a threshold nothing reaches. Lowering the floor here is actively dangerous, because you would be removing the standing capacity that has been silently compensating for a policy that does not work. Test the policy before you touch the floor.
Demand has not arrived yet. Provisioned for a launch or a season that has not happened. Fine, and worth an explicit review date rather than permanent spend.
Only the first is unambiguously waste, and no tool can tell you which case you are in from the outside. This is why the finding should quantify the cost and stop, rather than assert a saving.
Why we report this finding at zero dollars
An analyzer can price this precisely. It knows the instance type running in the group and can look up the hourly rate, so the monthly cost of one instance in the floor is straightforward arithmetic.
We put that number in the recommendation text and we do not add it to the report's savings total.
The reason is in the list above. We cannot see whether the floor encodes failover headroom, so we do not know that any instance can safely be removed. Banking a dollar figure on a reduction we are not confident enough to specify would mean the headline total contains savings nobody has agreed to and some of which should never be taken. The number belongs in the text where it informs the decision. It does not belong in a total that is supposed to represent money you can actually go and get.
The finding also deliberately models removing one instance, not collapsing the group to its observed demand. A group sitting at a floor of 6 with observed demand for 2 could in principle drop 4. Recommending that from the outside, with no view of the failover requirements the floor may encode, is exactly the kind of confident overreach that makes people stop trusting cost reports.
One more exclusion: groups with MinSize of 1 are skipped entirely. A single-instance floor cannot be lowered without emptying the group, so reporting it is unactionable noise.
Lowering a floor safely
One step at a time, verifying the policy still works between steps.
aws autoscaling update-auto-scaling-group \
--auto-scaling-group-name my-app-asg \
--min-size 5 \
--region ap-south-1
A workable sequence:
- Confirm group metrics are enabled and you have at least 30 days of history.
- Check the scaling policy has fired at some point in the past. If it never has, fix or test the policy first, because the floor may be compensating for it.
- Confirm the remaining floor still spans the Availability Zones you need.
- Lower
MinSizeby one. LeaveMaxSizealone, since the ceiling is not what you are paying for. - Wait through at least one full weekly cycle, including whatever your busiest day is.
- Repeat, or stop.
The reason for one step at a time is that the floor's purpose is often undocumented. Stepping down slowly turns an irreversible guess into a series of cheap, reversible experiments, and the cost of moving slowly is one month of one instance.
Frequently asked questions
What does MinSize actually cost in an Auto Scaling group?
MinSize is the capacity the group can never go below, so it is paid for around the clock regardless of demand. On a group whose scaling policy has never fired, the floor accounts for the entire compute cost of the group. Lowering it by one instance removes that instance's full monthly cost with no rebuild and no restart.
How do I tell if my Auto Scaling group's minimum is too high?
Compare the maximum of the GroupInServiceInstances metric in the AWS/AutoScaling namespace against the group's MinSize over at least 30 days. If the maximum never exceeded MinSize, the scaling policy has not fired in that period and the group has been sitting on its floor the whole time.
Why does AWS Compute Optimizer not flag an oversized Auto Scaling floor?
Because it analyses utilization, which asks whether each instance is the right size, not whether you need that many instances. Six instances at 65 percent CPU look healthy by that measure. The floor is a separate question that utilization data structurally cannot answer.
Why do my Auto Scaling groups have no CloudWatch metrics?
Auto Scaling group metrics are opt-in per group. Unless enable-metrics-collection was run on that specific group, GroupInServiceInstances does not exist for it and queries return nothing. Enabling it is free. Crucially, an absent series looks identical to a group that never scaled, so a tool that treats missing data as evidence will fabricate findings.
Is it safe to lower MinSize?
It depends on why the floor was set. A floor of 2 or 3 across Availability Zones is often deliberate fault tolerance, and lowering it is a real reduction in resilience rather than a free saving. A floor may also be silently compensating for a scaling policy that is broken and has never fired. Test the policy first, then lower by one step at a time and wait through a full weekly cycle between steps.
Why would a cost report show an Auto Scaling finding worth zero dollars?
Because the cost of an instance in the floor is knowable but the safe size of the reduction is not. A report cannot see whether the floor encodes failover headroom, so counting a saving would put money in the total that nobody has agreed to and some of which should never be taken. The per-instance figure belongs in the recommendation text, where it informs the decision without being counted as won.