The aws:autoscaling/policy:Policy resource, part of the Pulumi AWS provider, defines scaling policies that control when and how Auto Scaling groups add or remove instances. This guide focuses on three capabilities: simple fixed-adjustment scaling, target tracking with metric math, and predictive scaling with ML forecasting.
Scaling policies attach to existing Auto Scaling groups and may reference CloudWatch alarms, SQS queues, or load balancers as metric sources. The examples are intentionally small. Combine them with your own Auto Scaling groups, alarms, and monitoring infrastructure.
Scale by a fixed number of instances
Simple scaling policies add or remove a fixed number of instances when triggered, providing straightforward capacity adjustments.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const bar = new aws.autoscaling.Group("bar", {
availabilityZones: ["us-east-1a"],
name: "foobar3-test",
maxSize: 5,
minSize: 2,
healthCheckGracePeriod: 300,
healthCheckType: "ELB",
forceDelete: true,
launchConfiguration: foo.name,
});
const bat = new aws.autoscaling.Policy("bat", {
name: "foobar3-test",
scalingAdjustment: 4,
adjustmentType: "ChangeInCapacity",
cooldown: 300,
autoscalingGroupName: bar.name,
});
import pulumi
import pulumi_aws as aws
bar = aws.autoscaling.Group("bar",
availability_zones=["us-east-1a"],
name="foobar3-test",
max_size=5,
min_size=2,
health_check_grace_period=300,
health_check_type="ELB",
force_delete=True,
launch_configuration=foo["name"])
bat = aws.autoscaling.Policy("bat",
name="foobar3-test",
scaling_adjustment=4,
adjustment_type="ChangeInCapacity",
cooldown=300,
autoscaling_group_name=bar.name)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/autoscaling"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
bar, err := autoscaling.NewGroup(ctx, "bar", &autoscaling.GroupArgs{
AvailabilityZones: pulumi.StringArray{
pulumi.String("us-east-1a"),
},
Name: pulumi.String("foobar3-test"),
MaxSize: pulumi.Int(5),
MinSize: pulumi.Int(2),
HealthCheckGracePeriod: pulumi.Int(300),
HealthCheckType: pulumi.String("ELB"),
ForceDelete: pulumi.Bool(true),
LaunchConfiguration: pulumi.Any(foo.Name),
})
if err != nil {
return err
}
_, err = autoscaling.NewPolicy(ctx, "bat", &autoscaling.PolicyArgs{
Name: pulumi.String("foobar3-test"),
ScalingAdjustment: pulumi.Int(4),
AdjustmentType: pulumi.String("ChangeInCapacity"),
Cooldown: pulumi.Int(300),
AutoscalingGroupName: bar.Name,
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var bar = new Aws.AutoScaling.Group("bar", new()
{
AvailabilityZones = new[]
{
"us-east-1a",
},
Name = "foobar3-test",
MaxSize = 5,
MinSize = 2,
HealthCheckGracePeriod = 300,
HealthCheckType = "ELB",
ForceDelete = true,
LaunchConfiguration = foo.Name,
});
var bat = new Aws.AutoScaling.Policy("bat", new()
{
Name = "foobar3-test",
ScalingAdjustment = 4,
AdjustmentType = "ChangeInCapacity",
Cooldown = 300,
AutoscalingGroupName = bar.Name,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.autoscaling.Group;
import com.pulumi.aws.autoscaling.GroupArgs;
import com.pulumi.aws.autoscaling.Policy;
import com.pulumi.aws.autoscaling.PolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var bar = new Group("bar", GroupArgs.builder()
.availabilityZones("us-east-1a")
.name("foobar3-test")
.maxSize(5)
.minSize(2)
.healthCheckGracePeriod(300)
.healthCheckType("ELB")
.forceDelete(true)
.launchConfiguration(foo.name())
.build());
var bat = new Policy("bat", PolicyArgs.builder()
.name("foobar3-test")
.scalingAdjustment(4)
.adjustmentType("ChangeInCapacity")
.cooldown(300)
.autoscalingGroupName(bar.name())
.build());
}
}
resources:
bat:
type: aws:autoscaling:Policy
properties:
name: foobar3-test
scalingAdjustment: 4
adjustmentType: ChangeInCapacity
cooldown: 300
autoscalingGroupName: ${bar.name}
bar:
type: aws:autoscaling:Group
properties:
availabilityZones:
- us-east-1a
name: foobar3-test
maxSize: 5
minSize: 2
healthCheckGracePeriod: 300
healthCheckType: ELB
forceDelete: true
launchConfiguration: ${foo.name}
When the policy executes, it adds the number of instances specified in scalingAdjustment. The adjustmentType of “ChangeInCapacity” means the value is an absolute count, not a percentage. The cooldown period prevents rapid successive scaling actions, giving new instances time to start handling load before the next evaluation.
Maintain target metrics with calculated ratios
Target tracking policies automatically adjust capacity to maintain a metric at a target value. When monitoring a calculated ratio like messages per instance, you use metric math to combine CloudWatch data sources.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.autoscaling.Policy("example", {
autoscalingGroupName: "my-test-asg",
name: "foo",
policyType: "TargetTrackingScaling",
targetTrackingConfiguration: {
targetValue: 100,
customizedMetricSpecification: {
metrics: [
{
label: "Get the queue size (the number of messages waiting to be processed)",
id: "m1",
metricStat: {
metric: {
namespace: "AWS/SQS",
metricName: "ApproximateNumberOfMessagesVisible",
dimensions: [{
name: "QueueName",
value: "my-queue",
}],
},
stat: "Sum",
period: 10,
},
returnData: false,
},
{
label: "Get the group size (the number of InService instances)",
id: "m2",
metricStat: {
metric: {
namespace: "AWS/AutoScaling",
metricName: "GroupInServiceInstances",
dimensions: [{
name: "AutoScalingGroupName",
value: "my-asg",
}],
},
stat: "Average",
period: 10,
},
returnData: false,
},
{
label: "Calculate the backlog per instance",
id: "e1",
expression: "m1 / m2",
returnData: true,
},
],
},
},
});
import pulumi
import pulumi_aws as aws
example = aws.autoscaling.Policy("example",
autoscaling_group_name="my-test-asg",
name="foo",
policy_type="TargetTrackingScaling",
target_tracking_configuration={
"target_value": 100,
"customized_metric_specification": {
"metrics": [
{
"label": "Get the queue size (the number of messages waiting to be processed)",
"id": "m1",
"metric_stat": {
"metric": {
"namespace": "AWS/SQS",
"metric_name": "ApproximateNumberOfMessagesVisible",
"dimensions": [{
"name": "QueueName",
"value": "my-queue",
}],
},
"stat": "Sum",
"period": 10,
},
"return_data": False,
},
{
"label": "Get the group size (the number of InService instances)",
"id": "m2",
"metric_stat": {
"metric": {
"namespace": "AWS/AutoScaling",
"metric_name": "GroupInServiceInstances",
"dimensions": [{
"name": "AutoScalingGroupName",
"value": "my-asg",
}],
},
"stat": "Average",
"period": 10,
},
"return_data": False,
},
{
"label": "Calculate the backlog per instance",
"id": "e1",
"expression": "m1 / m2",
"return_data": True,
},
],
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/autoscaling"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := autoscaling.NewPolicy(ctx, "example", &autoscaling.PolicyArgs{
AutoscalingGroupName: pulumi.String("my-test-asg"),
Name: pulumi.String("foo"),
PolicyType: pulumi.String("TargetTrackingScaling"),
TargetTrackingConfiguration: &autoscaling.PolicyTargetTrackingConfigurationArgs{
TargetValue: pulumi.Float64(100),
CustomizedMetricSpecification: &autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationArgs{
Metrics: autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArray{
&autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs{
Label: pulumi.String("Get the queue size (the number of messages waiting to be processed)"),
Id: pulumi.String("m1"),
MetricStat: &autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatArgs{
Metric: &autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricArgs{
Namespace: pulumi.String("AWS/SQS"),
MetricName: pulumi.String("ApproximateNumberOfMessagesVisible"),
Dimensions: autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricDimensionArray{
&autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricDimensionArgs{
Name: pulumi.String("QueueName"),
Value: pulumi.String("my-queue"),
},
},
},
Stat: pulumi.String("Sum"),
Period: pulumi.Int(10),
},
ReturnData: pulumi.Bool(false),
},
&autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs{
Label: pulumi.String("Get the group size (the number of InService instances)"),
Id: pulumi.String("m2"),
MetricStat: &autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatArgs{
Metric: &autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricArgs{
Namespace: pulumi.String("AWS/AutoScaling"),
MetricName: pulumi.String("GroupInServiceInstances"),
Dimensions: autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricDimensionArray{
&autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricDimensionArgs{
Name: pulumi.String("AutoScalingGroupName"),
Value: pulumi.String("my-asg"),
},
},
},
Stat: pulumi.String("Average"),
Period: pulumi.Int(10),
},
ReturnData: pulumi.Bool(false),
},
&autoscaling.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs{
Label: pulumi.String("Calculate the backlog per instance"),
Id: pulumi.String("e1"),
Expression: pulumi.String("m1 / m2"),
ReturnData: pulumi.Bool(true),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AutoScaling.Policy("example", new()
{
AutoscalingGroupName = "my-test-asg",
Name = "foo",
PolicyType = "TargetTrackingScaling",
TargetTrackingConfiguration = new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationArgs
{
TargetValue = 100,
CustomizedMetricSpecification = new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationArgs
{
Metrics = new[]
{
new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs
{
Label = "Get the queue size (the number of messages waiting to be processed)",
Id = "m1",
MetricStat = new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatArgs
{
Metric = new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricArgs
{
Namespace = "AWS/SQS",
MetricName = "ApproximateNumberOfMessagesVisible",
Dimensions = new[]
{
new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricDimensionArgs
{
Name = "QueueName",
Value = "my-queue",
},
},
},
Stat = "Sum",
Period = 10,
},
ReturnData = false,
},
new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs
{
Label = "Get the group size (the number of InService instances)",
Id = "m2",
MetricStat = new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatArgs
{
Metric = new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricArgs
{
Namespace = "AWS/AutoScaling",
MetricName = "GroupInServiceInstances",
Dimensions = new[]
{
new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricDimensionArgs
{
Name = "AutoScalingGroupName",
Value = "my-asg",
},
},
},
Stat = "Average",
Period = 10,
},
ReturnData = false,
},
new Aws.AutoScaling.Inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs
{
Label = "Calculate the backlog per instance",
Id = "e1",
Expression = "m1 / m2",
ReturnData = true,
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.autoscaling.Policy;
import com.pulumi.aws.autoscaling.PolicyArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyTargetTrackingConfigurationArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyTargetTrackingConfigurationCustomizedMetricSpecificationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Policy("example", PolicyArgs.builder()
.autoscalingGroupName("my-test-asg")
.name("foo")
.policyType("TargetTrackingScaling")
.targetTrackingConfiguration(PolicyTargetTrackingConfigurationArgs.builder()
.targetValue(100.0)
.customizedMetricSpecification(PolicyTargetTrackingConfigurationCustomizedMetricSpecificationArgs.builder()
.metrics(
PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs.builder()
.label("Get the queue size (the number of messages waiting to be processed)")
.id("m1")
.metricStat(PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatArgs.builder()
.metric(PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricArgs.builder()
.namespace("AWS/SQS")
.metricName("ApproximateNumberOfMessagesVisible")
.dimensions(PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricDimensionArgs.builder()
.name("QueueName")
.value("my-queue")
.build())
.build())
.stat("Sum")
.period(10)
.build())
.returnData(false)
.build(),
PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs.builder()
.label("Get the group size (the number of InService instances)")
.id("m2")
.metricStat(PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatArgs.builder()
.metric(PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricArgs.builder()
.namespace("AWS/AutoScaling")
.metricName("GroupInServiceInstances")
.dimensions(PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricMetricStatMetricDimensionArgs.builder()
.name("AutoScalingGroupName")
.value("my-asg")
.build())
.build())
.stat("Average")
.period(10)
.build())
.returnData(false)
.build(),
PolicyTargetTrackingConfigurationCustomizedMetricSpecificationMetricArgs.builder()
.label("Calculate the backlog per instance")
.id("e1")
.expression("m1 / m2")
.returnData(true)
.build())
.build())
.build())
.build());
}
}
resources:
example:
type: aws:autoscaling:Policy
properties:
autoscalingGroupName: my-test-asg
name: foo
policyType: TargetTrackingScaling
targetTrackingConfiguration:
targetValue: 100
customizedMetricSpecification:
metrics:
- label: Get the queue size (the number of messages waiting to be processed)
id: m1
metricStat:
metric:
namespace: AWS/SQS
metricName: ApproximateNumberOfMessagesVisible
dimensions:
- name: QueueName
value: my-queue
stat: Sum
period: 10
returnData: false
- label: Get the group size (the number of InService instances)
id: m2
metricStat:
metric:
namespace: AWS/AutoScaling
metricName: GroupInServiceInstances
dimensions:
- name: AutoScalingGroupName
value: my-asg
stat: Average
period: 10
returnData: false
- label: Calculate the backlog per instance
id: e1
expression: m1 / m2
returnData: true
The policy calculates backlog per instance by dividing queue size by group size, then scales to keep that ratio at 100. The metricQueries array defines two input metrics (m1 for queue size, m2 for instance count) and one expression (e1) that divides them. Only the expression has returnData set to true, making it the value the policy tracks. AWS automatically scales in or out to maintain the target.
Forecast capacity with predictive scaling
Predictive scaling uses machine learning to forecast future load and scale proactively rather than waiting for metrics to breach thresholds.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.autoscaling.Policy("example", {
autoscalingGroupName: "my-test-asg",
name: "foo",
policyType: "PredictiveScaling",
predictiveScalingConfiguration: {
metricSpecification: {
targetValue: 10,
customizedLoadMetricSpecification: {
metricDataQueries: [{
id: "load_sum",
expression: "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 3600))",
}],
},
customizedCapacityMetricSpecification: {
metricDataQueries: [{
id: "capacity_sum",
expression: "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))",
}],
},
customizedScalingMetricSpecification: {
metricDataQueries: [
{
id: "capacity_sum",
expression: "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))",
returnData: false,
},
{
id: "load_sum",
expression: "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 300))",
returnData: false,
},
{
id: "weighted_average",
expression: "load_sum / (capacity_sum * PERIOD(capacity_sum) / 60)",
},
],
},
},
},
});
import pulumi
import pulumi_aws as aws
example = aws.autoscaling.Policy("example",
autoscaling_group_name="my-test-asg",
name="foo",
policy_type="PredictiveScaling",
predictive_scaling_configuration={
"metric_specification": {
"target_value": 10,
"customized_load_metric_specification": {
"metric_data_queries": [{
"id": "load_sum",
"expression": "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 3600))",
}],
},
"customized_capacity_metric_specification": {
"metric_data_queries": [{
"id": "capacity_sum",
"expression": "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))",
}],
},
"customized_scaling_metric_specification": {
"metric_data_queries": [
{
"id": "capacity_sum",
"expression": "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))",
"return_data": False,
},
{
"id": "load_sum",
"expression": "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 300))",
"return_data": False,
},
{
"id": "weighted_average",
"expression": "load_sum / (capacity_sum * PERIOD(capacity_sum) / 60)",
},
],
},
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/autoscaling"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := autoscaling.NewPolicy(ctx, "example", &autoscaling.PolicyArgs{
AutoscalingGroupName: pulumi.String("my-test-asg"),
Name: pulumi.String("foo"),
PolicyType: pulumi.String("PredictiveScaling"),
PredictiveScalingConfiguration: &autoscaling.PolicyPredictiveScalingConfigurationArgs{
MetricSpecification: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationArgs{
TargetValue: pulumi.Float64(10),
CustomizedLoadMetricSpecification: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedLoadMetricSpecificationArgs{
MetricDataQueries: autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedLoadMetricSpecificationMetricDataQueryArray{
&autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedLoadMetricSpecificationMetricDataQueryArgs{
Id: pulumi.String("load_sum"),
Expression: pulumi.String("SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 3600))"),
},
},
},
CustomizedCapacityMetricSpecification: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedCapacityMetricSpecificationArgs{
MetricDataQueries: autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedCapacityMetricSpecificationMetricDataQueryArray{
&autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedCapacityMetricSpecificationMetricDataQueryArgs{
Id: pulumi.String("capacity_sum"),
Expression: pulumi.String("SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))"),
},
},
},
CustomizedScalingMetricSpecification: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationArgs{
MetricDataQueries: autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArray{
&autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs{
Id: pulumi.String("capacity_sum"),
Expression: pulumi.String("SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))"),
ReturnData: pulumi.Bool(false),
},
&autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs{
Id: pulumi.String("load_sum"),
Expression: pulumi.String("SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 300))"),
ReturnData: pulumi.Bool(false),
},
&autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs{
Id: pulumi.String("weighted_average"),
Expression: pulumi.String("load_sum / (capacity_sum * PERIOD(capacity_sum) / 60)"),
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AutoScaling.Policy("example", new()
{
AutoscalingGroupName = "my-test-asg",
Name = "foo",
PolicyType = "PredictiveScaling",
PredictiveScalingConfiguration = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationArgs
{
MetricSpecification = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationArgs
{
TargetValue = 10,
CustomizedLoadMetricSpecification = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedLoadMetricSpecificationArgs
{
MetricDataQueries = new[]
{
new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedLoadMetricSpecificationMetricDataQueryArgs
{
Id = "load_sum",
Expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 3600))",
},
},
},
CustomizedCapacityMetricSpecification = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedCapacityMetricSpecificationArgs
{
MetricDataQueries = new[]
{
new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedCapacityMetricSpecificationMetricDataQueryArgs
{
Id = "capacity_sum",
Expression = "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))",
},
},
},
CustomizedScalingMetricSpecification = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationArgs
{
MetricDataQueries = new[]
{
new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs
{
Id = "capacity_sum",
Expression = "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))",
ReturnData = false,
},
new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs
{
Id = "load_sum",
Expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 300))",
ReturnData = false,
},
new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs
{
Id = "weighted_average",
Expression = "load_sum / (capacity_sum * PERIOD(capacity_sum) / 60)",
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.autoscaling.Policy;
import com.pulumi.aws.autoscaling.PolicyArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationMetricSpecificationArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedLoadMetricSpecificationArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedCapacityMetricSpecificationArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Policy("example", PolicyArgs.builder()
.autoscalingGroupName("my-test-asg")
.name("foo")
.policyType("PredictiveScaling")
.predictiveScalingConfiguration(PolicyPredictiveScalingConfigurationArgs.builder()
.metricSpecification(PolicyPredictiveScalingConfigurationMetricSpecificationArgs.builder()
.targetValue(10.0)
.customizedLoadMetricSpecification(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedLoadMetricSpecificationArgs.builder()
.metricDataQueries(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedLoadMetricSpecificationMetricDataQueryArgs.builder()
.id("load_sum")
.expression("SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 3600))")
.build())
.build())
.customizedCapacityMetricSpecification(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedCapacityMetricSpecificationArgs.builder()
.metricDataQueries(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedCapacityMetricSpecificationMetricDataQueryArgs.builder()
.id("capacity_sum")
.expression("SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))")
.build())
.build())
.customizedScalingMetricSpecification(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationArgs.builder()
.metricDataQueries(
PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs.builder()
.id("capacity_sum")
.expression("SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))")
.returnData(false)
.build(),
PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs.builder()
.id("load_sum")
.expression("SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 300))")
.returnData(false)
.build(),
PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs.builder()
.id("weighted_average")
.expression("load_sum / (capacity_sum * PERIOD(capacity_sum) / 60)")
.build())
.build())
.build())
.build())
.build());
}
}
resources:
example:
type: aws:autoscaling:Policy
properties:
autoscalingGroupName: my-test-asg
name: foo
policyType: PredictiveScaling
predictiveScalingConfiguration:
metricSpecification:
targetValue: 10
customizedLoadMetricSpecification:
metricDataQueries:
- id: load_sum
expression: SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName="CPUUtilization" my-test-asg', 'Sum', 3600))
customizedCapacityMetricSpecification:
metricDataQueries:
- id: capacity_sum
expression: SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName="GroupInServiceIntances" my-test-asg', 'Average', 300))
customizedScalingMetricSpecification:
metricDataQueries:
- id: capacity_sum
expression: SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName="GroupInServiceIntances" my-test-asg', 'Average', 300))
returnData: false
- id: load_sum
expression: SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName="CPUUtilization" my-test-asg', 'Sum', 300))
returnData: false
- id: weighted_average
expression: load_sum / (capacity_sum * PERIOD(capacity_sum) / 60)
The policy defines three metric specifications: load (CPU utilization), capacity (in-service instances), and scaling (weighted average). Each uses CloudWatch Metrics Insights SEARCH queries to aggregate historical data. The ML model learns daily and weekly patterns from this data, then scales ahead of predicted demand. The targetValue sets the desired scaling metric level.
Combine predefined load metrics with custom scaling
Predictive scaling can use AWS-provided metrics for load forecasting while applying custom metric math for scaling decisions.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.autoscaling.Policy("example", {
autoscalingGroupName: "my-test-asg",
name: "foo",
policyType: "PredictiveScaling",
predictiveScalingConfiguration: {
metricSpecification: {
targetValue: 10,
predefinedLoadMetricSpecification: {
predefinedMetricType: "ASGTotalCPUUtilization",
resourceLabel: "app/my-alb/778d41231b141a0f/targetgroup/my-alb-target-group/943f017f100becff",
},
customizedScalingMetricSpecification: {
metricDataQueries: [{
id: "scaling",
metricStat: {
metric: {
metricName: "CPUUtilization",
namespace: "AWS/EC2",
dimensions: [{
name: "AutoScalingGroupName",
value: "my-test-asg",
}],
},
stat: "Average",
},
}],
},
},
},
});
import pulumi
import pulumi_aws as aws
example = aws.autoscaling.Policy("example",
autoscaling_group_name="my-test-asg",
name="foo",
policy_type="PredictiveScaling",
predictive_scaling_configuration={
"metric_specification": {
"target_value": 10,
"predefined_load_metric_specification": {
"predefined_metric_type": "ASGTotalCPUUtilization",
"resource_label": "app/my-alb/778d41231b141a0f/targetgroup/my-alb-target-group/943f017f100becff",
},
"customized_scaling_metric_specification": {
"metric_data_queries": [{
"id": "scaling",
"metric_stat": {
"metric": {
"metric_name": "CPUUtilization",
"namespace": "AWS/EC2",
"dimensions": [{
"name": "AutoScalingGroupName",
"value": "my-test-asg",
}],
},
"stat": "Average",
},
}],
},
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/autoscaling"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := autoscaling.NewPolicy(ctx, "example", &autoscaling.PolicyArgs{
AutoscalingGroupName: pulumi.String("my-test-asg"),
Name: pulumi.String("foo"),
PolicyType: pulumi.String("PredictiveScaling"),
PredictiveScalingConfiguration: &autoscaling.PolicyPredictiveScalingConfigurationArgs{
MetricSpecification: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationArgs{
TargetValue: pulumi.Float64(10),
PredefinedLoadMetricSpecification: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationPredefinedLoadMetricSpecificationArgs{
PredefinedMetricType: pulumi.String("ASGTotalCPUUtilization"),
ResourceLabel: pulumi.String("app/my-alb/778d41231b141a0f/targetgroup/my-alb-target-group/943f017f100becff"),
},
CustomizedScalingMetricSpecification: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationArgs{
MetricDataQueries: autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArray{
&autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs{
Id: pulumi.String("scaling"),
MetricStat: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatArgs{
Metric: &autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatMetricArgs{
MetricName: pulumi.String("CPUUtilization"),
Namespace: pulumi.String("AWS/EC2"),
Dimensions: autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatMetricDimensionArray{
&autoscaling.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatMetricDimensionArgs{
Name: pulumi.String("AutoScalingGroupName"),
Value: pulumi.String("my-test-asg"),
},
},
},
Stat: pulumi.String("Average"),
},
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AutoScaling.Policy("example", new()
{
AutoscalingGroupName = "my-test-asg",
Name = "foo",
PolicyType = "PredictiveScaling",
PredictiveScalingConfiguration = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationArgs
{
MetricSpecification = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationArgs
{
TargetValue = 10,
PredefinedLoadMetricSpecification = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationPredefinedLoadMetricSpecificationArgs
{
PredefinedMetricType = "ASGTotalCPUUtilization",
ResourceLabel = "app/my-alb/778d41231b141a0f/targetgroup/my-alb-target-group/943f017f100becff",
},
CustomizedScalingMetricSpecification = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationArgs
{
MetricDataQueries = new[]
{
new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs
{
Id = "scaling",
MetricStat = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatArgs
{
Metric = new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatMetricArgs
{
MetricName = "CPUUtilization",
Namespace = "AWS/EC2",
Dimensions = new[]
{
new Aws.AutoScaling.Inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatMetricDimensionArgs
{
Name = "AutoScalingGroupName",
Value = "my-test-asg",
},
},
},
Stat = "Average",
},
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.autoscaling.Policy;
import com.pulumi.aws.autoscaling.PolicyArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationMetricSpecificationArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationMetricSpecificationPredefinedLoadMetricSpecificationArgs;
import com.pulumi.aws.autoscaling.inputs.PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Policy("example", PolicyArgs.builder()
.autoscalingGroupName("my-test-asg")
.name("foo")
.policyType("PredictiveScaling")
.predictiveScalingConfiguration(PolicyPredictiveScalingConfigurationArgs.builder()
.metricSpecification(PolicyPredictiveScalingConfigurationMetricSpecificationArgs.builder()
.targetValue(10.0)
.predefinedLoadMetricSpecification(PolicyPredictiveScalingConfigurationMetricSpecificationPredefinedLoadMetricSpecificationArgs.builder()
.predefinedMetricType("ASGTotalCPUUtilization")
.resourceLabel("app/my-alb/778d41231b141a0f/targetgroup/my-alb-target-group/943f017f100becff")
.build())
.customizedScalingMetricSpecification(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationArgs.builder()
.metricDataQueries(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryArgs.builder()
.id("scaling")
.metricStat(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatArgs.builder()
.metric(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatMetricArgs.builder()
.metricName("CPUUtilization")
.namespace("AWS/EC2")
.dimensions(PolicyPredictiveScalingConfigurationMetricSpecificationCustomizedScalingMetricSpecificationMetricDataQueryMetricStatMetricDimensionArgs.builder()
.name("AutoScalingGroupName")
.value("my-test-asg")
.build())
.build())
.stat("Average")
.build())
.build())
.build())
.build())
.build())
.build());
}
}
resources:
example:
type: aws:autoscaling:Policy
properties:
autoscalingGroupName: my-test-asg
name: foo
policyType: PredictiveScaling
predictiveScalingConfiguration:
metricSpecification:
targetValue: 10
predefinedLoadMetricSpecification:
predefinedMetricType: ASGTotalCPUUtilization
resourceLabel: app/my-alb/778d41231b141a0f/targetgroup/my-alb-target-group/943f017f100becff
customizedScalingMetricSpecification:
metricDataQueries:
- id: scaling
metricStat:
metric:
metricName: CPUUtilization
namespace: AWS/EC2
dimensions:
- name: AutoScalingGroupName
value: my-test-asg
stat: Average
The predefinedLoadMetricSpecification uses AWS’s built-in CPU utilization metric for forecasting, simplifying configuration. The customizedScalingMetricSpecification still uses custom metric math to define how scaling decisions are made. This hybrid approach works well when AWS metrics match your load patterns but you need custom scaling logic.
Beyond these examples
These snippets focus on specific policy-level features: simple and target tracking scaling, metric math and Metrics Insights queries, and predictive scaling with ML forecasting. They’re intentionally minimal rather than full Auto Scaling deployments.
The examples reference pre-existing infrastructure such as Auto Scaling groups, CloudWatch alarms (for simple scaling), and SQS queues or load balancers (for metric sources). They focus on configuring the policy rather than provisioning the surrounding infrastructure.
To keep things focused, common policy patterns are omitted, including:
- Step scaling with multiple threshold ranges
- Warmup periods and cooldown tuning
- Scaling policy disablement (enabled property)
- CloudWatch alarm integration details
These omissions are intentional: the goal is to illustrate how each policy type is wired, not provide drop-in scaling modules. See the AutoScaling Policy resource reference for all available configuration options.
Let's configure AWS Auto Scaling Policies
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Best Practices
desiredCapacity from the aws.autoscaling.Group when using autoscaling policies. It’s good practice to choose either manual scaling (with desiredCapacity) or dynamic policy-based scaling, but not both, to avoid conflicts.SimpleScaling, StepScaling, TargetTrackingScaling, and PredictiveScaling. If you don’t specify policyType, AWS defaults to SimpleScaling.adjustmentType determines whether the scaling adjustment is an absolute number or a percentage of current capacity. Valid values are ChangeInCapacity, ExactCapacity, and PercentChangeInCapacity.Scaling Adjustments & Timing
cooldown is the time in seconds after a scaling activity completes before the next scaling activity can start. estimatedInstanceWarmup is the estimated time until a newly launched instance contributes CloudWatch metrics. If you don’t specify estimatedInstanceWarmup, AWS defaults to the group’s cooldown period.scalingAdjustment to scale up and a negative value to scale down. This property is only available for SimpleScaling type policies.stepAdjustments array with objects containing scalingAdjustment, metricIntervalLowerBound, and metricIntervalUpperBound for each threshold range. Each step defines how much to scale when metrics fall within that interval.Policy Types & Advanced Features
TargetTrackingScaling with customizedMetricSpecification and metric math. Create metrics for queue size (ApproximateNumberOfMessagesVisible) and group size (GroupInServiceInstances), then use an expression like m1 / m2 to calculate backlog per instance.predictiveScalingConfiguration with customizedLoadMetricSpecification, customizedCapacityMetricSpecification, and customizedScalingMetricSpecification using CloudWatch metric queries or expressions.predefinedLoadMetricSpecification (like ASGTotalCPUUtilization) alongside customizedScalingMetricSpecification or other customized metric specifications.policyType to TargetTrackingScaling and configure targetTrackingConfiguration with predefinedMetricSpecification using ASGAverageCPUUtilization as the predefinedMetricType, then specify your desired targetValue.Resource Management
autoscalingGroupName and name are immutable. Changing either property will force replacement of the policy resource.enabled to false to disable the policy. The default value is true.