The aws:autoscaling/policy:Policy resource, part of the Pulumi AWS provider, defines Auto Scaling policies that adjust group capacity based on metrics, thresholds, or forecasts. This guide focuses on three capabilities: simple scaling with fixed adjustments, target tracking with calculated metrics, and predictive scaling with custom and predefined metrics.
Policies attach to existing Auto Scaling groups and may reference CloudWatch alarms, SQS queues, or ALB target groups as metric sources. The examples are intentionally small. Combine them with your own Auto Scaling groups, alarms, and metric sources.
Scale by a fixed amount on demand
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 a CloudWatch alarm fires, the policy adds the number of instances specified in scalingAdjustment. The adjustmentType of “ChangeInCapacity” means the value is added directly to current capacity. The cooldown period prevents rapid successive scaling actions.
Maintain target value using calculated metrics
Target tracking policies automatically adjust capacity to keep a metric at a specified target, calculating the right scaling actions based on current state.
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 SQS queue size by the number of running instances, then scales to maintain 100 messages per instance. The targetTrackingConfiguration defines the target value and metric calculation. Each metric query in the metrics array either fetches data (returnData: false) or computes a derived value (returnData: true). The expression “m1 / m2” divides queue size by instance count.
Forecast capacity needs with custom metrics
Predictive scaling analyzes historical patterns to forecast future load and pre-scale capacity before demand arrives.
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 predictiveScalingConfiguration uses three metric specifications: customizedLoadMetricSpecification tracks incoming demand, customizedCapacityMetricSpecification measures current capacity, and customizedScalingMetricSpecification calculates the ratio that drives scaling decisions. Each uses CloudWatch Metrics Insights queries (SEARCH expressions) to aggregate metrics across the Auto Scaling group. The policy forecasts load patterns and scales proactively.
Combine predefined and custom metrics for forecasting
Predictive policies can mix AWS-provided load metrics with custom scaling metrics, simplifying configuration when standard load patterns apply.
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 ALB request count metric, identified by the resourceLabel pointing to your target group. The customizedScalingMetricSpecification defines how to calculate the scaling metric from EC2 CPU utilization. This hybrid approach reduces configuration complexity when standard load metrics fit your use case.
Beyond these examples
These snippets focus on specific policy-level features: simple, target tracking, and predictive scaling; metric math and custom metric specifications; and predefined and customized metric combinations. They’re intentionally minimal rather than full Auto Scaling solutions.
The examples reference pre-existing infrastructure such as Auto Scaling groups, CloudWatch alarms (for simple scaling), and SQS queues or ALB target groups (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 adjustment thresholds
- Warmup periods and cooldown tuning (estimatedInstanceWarmup)
- Policy enable/disable controls (enabled property)
- Minimum adjustment magnitude for percentage-based scaling
These omissions are intentional: the goal is to illustrate how each policy type is wired, not provide drop-in scaling modules. See the Auto Scaling 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
Policy Types & Configuration
SimpleScaling, StepScaling, TargetTrackingScaling, and PredictiveScaling. If you don’t specify policyType, AWS defaults to SimpleScaling.ChangeInCapacity adds or subtracts instances, ExactCapacity sets the group to a specific size, and PercentChangeInCapacity scales by a percentage of current capacity.desiredCapacity from the aws.autoscaling.Group when using autoscaling policies. Mixing manual scaling (via desiredCapacity) with dynamic policy-based scaling can cause conflicts.enabled property, which accepts a boolean value and defaults to true. Set it to false to disable the policy without deleting it.Scaling Behavior & Timing
cooldown is the time in seconds after a scaling activity completes before the next scaling activity can start. estimatedInstanceWarmup is the time until a newly launched instance contributes CloudWatch metrics. If you don’t specify estimatedInstanceWarmup, AWS uses the group’s cooldown period.Average aggregation. Valid values are Minimum, Maximum, and Average.Advanced Features
policyType to TargetTrackingScaling and configure targetTrackingConfiguration with either a predefinedMetricSpecification (like ASGAverageCPUUtilization) or a customizedMetricSpecification for custom metrics.customizedMetricSpecification.metrics, each with a unique id. Use the expression field to combine metrics mathematically (e.g., m1 / m2 for backlog per instance). Set returnData: true on the final calculated metric and false on input metrics.stepAdjustments array with objects containing scalingAdjustment, metricIntervalLowerBound, and metricIntervalUpperBound. Each step defines a different scaling action based on metric threshold ranges.policyType to PredictiveScaling and configure predictiveScalingConfiguration.metricSpecification with load, capacity, and scaling metrics. You can use predefined metrics (like ASGTotalCPUUtilization) or customized metric specifications with CloudWatch metric queries.Common Issues & Limitations
autoscalingGroupName and name are immutable. Changing either requires replacing the policy resource.minAdjustmentMagnitude sets the minimum number of instances to scale when adjustmentType is PercentChangeInCapacity. This ensures small percentage changes still scale by at least this many instances.