The aws:budgets/budget:Budget resource, part of the Pulumi AWS provider, defines AWS Budgets that track spending or usage against limits and send notifications when thresholds are breached. This guide focuses on three capabilities: cost and usage budget types, email notifications and forecasted alerts, and filter expressions for service, tag, and region filtering.
Budgets operate at the AWS account level and reference existing services, tags, and cost categories. The examples are intentionally small. Combine them with your own notification targets and organizational tagging strategy.
Track EC2 costs with email notifications
Most budget deployments start by setting cost limits for specific services and configuring alerts when forecasted spending approaches those limits.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const ec2 = new aws.budgets.Budget("ec2", {
name: "budget-ec2-monthly",
budgetType: "COST",
limitAmount: "1200",
limitUnit: "USD",
timePeriodEnd: "2087-06-15_00:00",
timePeriodStart: "2017-07-01_00:00",
timeUnit: "MONTHLY",
costFilters: [{
name: "Service",
values: ["Amazon Elastic Compute Cloud - Compute"],
}],
notifications: [{
comparisonOperator: "GREATER_THAN",
threshold: 100,
thresholdType: "PERCENTAGE",
notificationType: "FORECASTED",
subscriberEmailAddresses: ["test@example.com"],
}],
tags: {
Tag1: "Value1",
Tag2: "Value2",
},
});
import pulumi
import pulumi_aws as aws
ec2 = aws.budgets.Budget("ec2",
name="budget-ec2-monthly",
budget_type="COST",
limit_amount="1200",
limit_unit="USD",
time_period_end="2087-06-15_00:00",
time_period_start="2017-07-01_00:00",
time_unit="MONTHLY",
cost_filters=[{
"name": "Service",
"values": ["Amazon Elastic Compute Cloud - Compute"],
}],
notifications=[{
"comparison_operator": "GREATER_THAN",
"threshold": 100,
"threshold_type": "PERCENTAGE",
"notification_type": "FORECASTED",
"subscriber_email_addresses": ["test@example.com"],
}],
tags={
"Tag1": "Value1",
"Tag2": "Value2",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/budgets"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := budgets.NewBudget(ctx, "ec2", &budgets.BudgetArgs{
Name: pulumi.String("budget-ec2-monthly"),
BudgetType: pulumi.String("COST"),
LimitAmount: pulumi.String("1200"),
LimitUnit: pulumi.String("USD"),
TimePeriodEnd: pulumi.String("2087-06-15_00:00"),
TimePeriodStart: pulumi.String("2017-07-01_00:00"),
TimeUnit: pulumi.String("MONTHLY"),
CostFilters: budgets.BudgetCostFilterArray{
&budgets.BudgetCostFilterArgs{
Name: pulumi.String("Service"),
Values: pulumi.StringArray{
pulumi.String("Amazon Elastic Compute Cloud - Compute"),
},
},
},
Notifications: budgets.BudgetNotificationArray{
&budgets.BudgetNotificationArgs{
ComparisonOperator: pulumi.String("GREATER_THAN"),
Threshold: pulumi.Float64(100),
ThresholdType: pulumi.String("PERCENTAGE"),
NotificationType: pulumi.String("FORECASTED"),
SubscriberEmailAddresses: pulumi.StringArray{
pulumi.String("test@example.com"),
},
},
},
Tags: pulumi.StringMap{
"Tag1": pulumi.String("Value1"),
"Tag2": pulumi.String("Value2"),
},
})
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 ec2 = new Aws.Budgets.Budget("ec2", new()
{
Name = "budget-ec2-monthly",
BudgetType = "COST",
LimitAmount = "1200",
LimitUnit = "USD",
TimePeriodEnd = "2087-06-15_00:00",
TimePeriodStart = "2017-07-01_00:00",
TimeUnit = "MONTHLY",
CostFilters = new[]
{
new Aws.Budgets.Inputs.BudgetCostFilterArgs
{
Name = "Service",
Values = new[]
{
"Amazon Elastic Compute Cloud - Compute",
},
},
},
Notifications = new[]
{
new Aws.Budgets.Inputs.BudgetNotificationArgs
{
ComparisonOperator = "GREATER_THAN",
Threshold = 100,
ThresholdType = "PERCENTAGE",
NotificationType = "FORECASTED",
SubscriberEmailAddresses = new[]
{
"test@example.com",
},
},
},
Tags =
{
{ "Tag1", "Value1" },
{ "Tag2", "Value2" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.budgets.Budget;
import com.pulumi.aws.budgets.BudgetArgs;
import com.pulumi.aws.budgets.inputs.BudgetCostFilterArgs;
import com.pulumi.aws.budgets.inputs.BudgetNotificationArgs;
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 ec2 = new Budget("ec2", BudgetArgs.builder()
.name("budget-ec2-monthly")
.budgetType("COST")
.limitAmount("1200")
.limitUnit("USD")
.timePeriodEnd("2087-06-15_00:00")
.timePeriodStart("2017-07-01_00:00")
.timeUnit("MONTHLY")
.costFilters(BudgetCostFilterArgs.builder()
.name("Service")
.values("Amazon Elastic Compute Cloud - Compute")
.build())
.notifications(BudgetNotificationArgs.builder()
.comparisonOperator("GREATER_THAN")
.threshold(100.0)
.thresholdType("PERCENTAGE")
.notificationType("FORECASTED")
.subscriberEmailAddresses("test@example.com")
.build())
.tags(Map.ofEntries(
Map.entry("Tag1", "Value1"),
Map.entry("Tag2", "Value2")
))
.build());
}
}
resources:
ec2:
type: aws:budgets:Budget
properties:
name: budget-ec2-monthly
budgetType: COST
limitAmount: '1200'
limitUnit: USD
timePeriodEnd: 2087-06-15_00:00
timePeriodStart: 2017-07-01_00:00
timeUnit: MONTHLY
costFilters:
- name: Service
values:
- Amazon Elastic Compute Cloud - Compute
notifications:
- comparisonOperator: GREATER_THAN
threshold: 100
thresholdType: PERCENTAGE
notificationType: FORECASTED
subscriberEmailAddresses:
- test@example.com
tags:
Tag1: Value1
Tag2: Value2
When AWS forecasts that your spending will exceed the threshold, it sends email notifications to the specified addresses. The budgetType determines whether you’re tracking cost or usage; costFilters narrows the scope to specific services. The notifications array defines when alerts fire: comparisonOperator sets the comparison logic, threshold sets the percentage, and notificationType controls whether you alert on actual or forecasted spending.
Define variable spending limits over time
Organizations with seasonal workloads or phased rollouts need budgets that adjust month-to-month rather than using a single fixed limit.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const cost = new aws.budgets.Budget("cost", {plannedLimits: [
{
startTime: "2017-07-01_00:00",
amount: "100",
unit: "USD",
},
{
startTime: "2017-08-01_00:00",
amount: "200",
unit: "USD",
},
]});
import pulumi
import pulumi_aws as aws
cost = aws.budgets.Budget("cost", planned_limits=[
{
"start_time": "2017-07-01_00:00",
"amount": "100",
"unit": "USD",
},
{
"start_time": "2017-08-01_00:00",
"amount": "200",
"unit": "USD",
},
])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/budgets"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := budgets.NewBudget(ctx, "cost", &budgets.BudgetArgs{
PlannedLimits: budgets.BudgetPlannedLimitArray{
&budgets.BudgetPlannedLimitArgs{
StartTime: pulumi.String("2017-07-01_00:00"),
Amount: pulumi.String("100"),
Unit: pulumi.String("USD"),
},
&budgets.BudgetPlannedLimitArgs{
StartTime: pulumi.String("2017-08-01_00:00"),
Amount: pulumi.String("200"),
Unit: pulumi.String("USD"),
},
},
})
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 cost = new Aws.Budgets.Budget("cost", new()
{
PlannedLimits = new[]
{
new Aws.Budgets.Inputs.BudgetPlannedLimitArgs
{
StartTime = "2017-07-01_00:00",
Amount = "100",
Unit = "USD",
},
new Aws.Budgets.Inputs.BudgetPlannedLimitArgs
{
StartTime = "2017-08-01_00:00",
Amount = "200",
Unit = "USD",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.budgets.Budget;
import com.pulumi.aws.budgets.BudgetArgs;
import com.pulumi.aws.budgets.inputs.BudgetPlannedLimitArgs;
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 cost = new Budget("cost", BudgetArgs.builder()
.plannedLimits(
BudgetPlannedLimitArgs.builder()
.startTime("2017-07-01_00:00")
.amount("100")
.unit("USD")
.build(),
BudgetPlannedLimitArgs.builder()
.startTime("2017-08-01_00:00")
.amount("200")
.unit("USD")
.build())
.build());
}
}
resources:
cost:
type: aws:budgets:Budget
properties:
plannedLimits:
- startTime: 2017-07-01_00:00
amount: '100'
unit: USD
- startTime: 2017-08-01_00:00
amount: '200'
unit: USD
The plannedLimits array replaces the single limitAmount property, allowing you to define different budget amounts for different time periods. Each entry specifies a startTime and the amount that applies from that date forward. This approach works well for projects with known spending ramps or seasonal traffic patterns.
Monitor S3 storage usage in gigabytes
Usage budgets track resource consumption rather than cost, useful for monitoring storage quotas or data transfer limits.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const s3 = new aws.budgets.Budget("s3", {
budgetType: "USAGE",
limitAmount: "3",
limitUnit: "GB",
});
import pulumi
import pulumi_aws as aws
s3 = aws.budgets.Budget("s3",
budget_type="USAGE",
limit_amount="3",
limit_unit="GB")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/budgets"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := budgets.NewBudget(ctx, "s3", &budgets.BudgetArgs{
BudgetType: pulumi.String("USAGE"),
LimitAmount: pulumi.String("3"),
LimitUnit: pulumi.String("GB"),
})
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 s3 = new Aws.Budgets.Budget("s3", new()
{
BudgetType = "USAGE",
LimitAmount = "3",
LimitUnit = "GB",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.budgets.Budget;
import com.pulumi.aws.budgets.BudgetArgs;
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 s3 = new Budget("s3", BudgetArgs.builder()
.budgetType("USAGE")
.limitAmount("3")
.limitUnit("GB")
.build());
}
}
resources:
s3:
type: aws:budgets:Budget
properties:
budgetType: USAGE
limitAmount: '3'
limitUnit: GB
Setting budgetType to USAGE shifts from dollar amounts to resource units. The limitUnit changes from USD to GB, and the budget tracks storage consumption rather than spending. This configuration alerts when storage exceeds the specified gigabyte threshold, regardless of pricing changes.
Track Savings Plan utilization percentage
Organizations with Savings Plans commitments need to monitor utilization rates to ensure they’re maximizing their commitment value.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const savingsPlanUtilization = new aws.budgets.Budget("savings_plan_utilization", {
budgetType: "SAVINGS_PLANS_UTILIZATION",
limitAmount: "100.0",
limitUnit: "PERCENTAGE",
costTypes: {
includeCredit: false,
includeDiscount: false,
includeOtherSubscription: false,
includeRecurring: false,
includeRefund: false,
includeSubscription: true,
includeSupport: false,
includeTax: false,
includeUpfront: false,
useBlended: false,
},
});
import pulumi
import pulumi_aws as aws
savings_plan_utilization = aws.budgets.Budget("savings_plan_utilization",
budget_type="SAVINGS_PLANS_UTILIZATION",
limit_amount="100.0",
limit_unit="PERCENTAGE",
cost_types={
"include_credit": False,
"include_discount": False,
"include_other_subscription": False,
"include_recurring": False,
"include_refund": False,
"include_subscription": True,
"include_support": False,
"include_tax": False,
"include_upfront": False,
"use_blended": False,
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/budgets"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := budgets.NewBudget(ctx, "savings_plan_utilization", &budgets.BudgetArgs{
BudgetType: pulumi.String("SAVINGS_PLANS_UTILIZATION"),
LimitAmount: pulumi.String("100.0"),
LimitUnit: pulumi.String("PERCENTAGE"),
CostTypes: &budgets.BudgetCostTypesArgs{
IncludeCredit: pulumi.Bool(false),
IncludeDiscount: pulumi.Bool(false),
IncludeOtherSubscription: pulumi.Bool(false),
IncludeRecurring: pulumi.Bool(false),
IncludeRefund: pulumi.Bool(false),
IncludeSubscription: pulumi.Bool(true),
IncludeSupport: pulumi.Bool(false),
IncludeTax: pulumi.Bool(false),
IncludeUpfront: pulumi.Bool(false),
UseBlended: pulumi.Bool(false),
},
})
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 savingsPlanUtilization = new Aws.Budgets.Budget("savings_plan_utilization", new()
{
BudgetType = "SAVINGS_PLANS_UTILIZATION",
LimitAmount = "100.0",
LimitUnit = "PERCENTAGE",
CostTypes = new Aws.Budgets.Inputs.BudgetCostTypesArgs
{
IncludeCredit = false,
IncludeDiscount = false,
IncludeOtherSubscription = false,
IncludeRecurring = false,
IncludeRefund = false,
IncludeSubscription = true,
IncludeSupport = false,
IncludeTax = false,
IncludeUpfront = false,
UseBlended = false,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.budgets.Budget;
import com.pulumi.aws.budgets.BudgetArgs;
import com.pulumi.aws.budgets.inputs.BudgetCostTypesArgs;
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 savingsPlanUtilization = new Budget("savingsPlanUtilization", BudgetArgs.builder()
.budgetType("SAVINGS_PLANS_UTILIZATION")
.limitAmount("100.0")
.limitUnit("PERCENTAGE")
.costTypes(BudgetCostTypesArgs.builder()
.includeCredit(false)
.includeDiscount(false)
.includeOtherSubscription(false)
.includeRecurring(false)
.includeRefund(false)
.includeSubscription(true)
.includeSupport(false)
.includeTax(false)
.includeUpfront(false)
.useBlended(false)
.build())
.build());
}
}
resources:
savingsPlanUtilization:
type: aws:budgets:Budget
name: savings_plan_utilization
properties:
budgetType: SAVINGS_PLANS_UTILIZATION
limitAmount: '100.0'
limitUnit: PERCENTAGE
costTypes:
includeCredit: false
includeDiscount: false
includeOtherSubscription: false
includeRecurring: false
includeRefund: false
includeSubscription: true
includeSupport: false
includeTax: false
includeUpfront: false
useBlended: false
Savings Plan utilization budgets use PERCENTAGE as the limitUnit and require specific costTypes configuration. Setting includeSubscription to true ensures the budget tracks your commitment usage. The other costTypes flags control which cost components factor into the calculation; for utilization tracking, most are set to false to focus purely on commitment usage.
Filter costs using dimension expressions
The filterExpression property provides more flexible cost filtering than the legacy costFilters array, supporting complex logical operations.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const simple = new aws.budgets.Budget("simple", {
name: "budget-ec2-filter",
budgetType: "COST",
limitAmount: "500",
limitUnit: "USD",
timeUnit: "MONTHLY",
filterExpression: {
dimensions: {
key: "SERVICE",
values: ["Amazon Elastic Compute Cloud - Compute"],
},
},
});
import pulumi
import pulumi_aws as aws
simple = aws.budgets.Budget("simple",
name="budget-ec2-filter",
budget_type="COST",
limit_amount="500",
limit_unit="USD",
time_unit="MONTHLY",
filter_expression={
"dimensions": {
"key": "SERVICE",
"values": ["Amazon Elastic Compute Cloud - Compute"],
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/budgets"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := budgets.NewBudget(ctx, "simple", &budgets.BudgetArgs{
Name: pulumi.String("budget-ec2-filter"),
BudgetType: pulumi.String("COST"),
LimitAmount: pulumi.String("500"),
LimitUnit: pulumi.String("USD"),
TimeUnit: pulumi.String("MONTHLY"),
FilterExpression: &budgets.BudgetFilterExpressionArgs{
Dimensions: &budgets.BudgetFilterExpressionDimensionsArgs{
Key: pulumi.String("SERVICE"),
Values: pulumi.StringArray{
pulumi.String("Amazon Elastic Compute Cloud - Compute"),
},
},
},
})
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 simple = new Aws.Budgets.Budget("simple", new()
{
Name = "budget-ec2-filter",
BudgetType = "COST",
LimitAmount = "500",
LimitUnit = "USD",
TimeUnit = "MONTHLY",
FilterExpression = new Aws.Budgets.Inputs.BudgetFilterExpressionArgs
{
Dimensions = new Aws.Budgets.Inputs.BudgetFilterExpressionDimensionsArgs
{
Key = "SERVICE",
Values = new[]
{
"Amazon Elastic Compute Cloud - Compute",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.budgets.Budget;
import com.pulumi.aws.budgets.BudgetArgs;
import com.pulumi.aws.budgets.inputs.BudgetFilterExpressionArgs;
import com.pulumi.aws.budgets.inputs.BudgetFilterExpressionDimensionsArgs;
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 simple = new Budget("simple", BudgetArgs.builder()
.name("budget-ec2-filter")
.budgetType("COST")
.limitAmount("500")
.limitUnit("USD")
.timeUnit("MONTHLY")
.filterExpression(BudgetFilterExpressionArgs.builder()
.dimensions(BudgetFilterExpressionDimensionsArgs.builder()
.key("SERVICE")
.values("Amazon Elastic Compute Cloud - Compute")
.build())
.build())
.build());
}
}
resources:
simple:
type: aws:budgets:Budget
properties:
name: budget-ec2-filter
budgetType: COST
limitAmount: '500'
limitUnit: USD
timeUnit: MONTHLY
filterExpression:
dimensions:
key: SERVICE
values:
- Amazon Elastic Compute Cloud - Compute
Filter expressions use a structured format with dimensions, tags, and costCategories objects. The dimensions object filters by AWS-defined attributes like SERVICE or REGION. This approach replaces the older costFilters array and enables more complex filtering logic in subsequent examples.
Combine multiple filters with AND logic
Production cost tracking often requires filtering by both service type and environment tags to isolate specific workload costs.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const andExample = new aws.budgets.Budget("and_example", {
name: "budget-and-filter",
budgetType: "COST",
limitAmount: "1200",
limitUnit: "USD",
timeUnit: "MONTHLY",
filterExpression: {
ands: [
{
dimensions: {
key: "SERVICE",
values: ["Amazon Elastic Compute Cloud - Compute"],
},
},
{
tags: {
key: "Environment",
values: ["Production"],
},
},
],
},
});
import pulumi
import pulumi_aws as aws
and_example = aws.budgets.Budget("and_example",
name="budget-and-filter",
budget_type="COST",
limit_amount="1200",
limit_unit="USD",
time_unit="MONTHLY",
filter_expression={
"ands": [
{
"dimensions": {
"key": "SERVICE",
"values": ["Amazon Elastic Compute Cloud - Compute"],
},
},
{
"tags": {
"key": "Environment",
"values": ["Production"],
},
},
],
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/budgets"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := budgets.NewBudget(ctx, "and_example", &budgets.BudgetArgs{
Name: pulumi.String("budget-and-filter"),
BudgetType: pulumi.String("COST"),
LimitAmount: pulumi.String("1200"),
LimitUnit: pulumi.String("USD"),
TimeUnit: pulumi.String("MONTHLY"),
FilterExpression: &budgets.BudgetFilterExpressionArgs{
Ands: budgets.BudgetFilterExpressionAndArray{
&budgets.BudgetFilterExpressionAndArgs{
Dimensions: &budgets.BudgetFilterExpressionAndDimensionsArgs{
Key: pulumi.String("SERVICE"),
Values: pulumi.StringArray{
pulumi.String("Amazon Elastic Compute Cloud - Compute"),
},
},
},
&budgets.BudgetFilterExpressionAndArgs{
Tags: &budgets.BudgetFilterExpressionAndTagsArgs{
Key: pulumi.String("Environment"),
Values: pulumi.StringArray{
pulumi.String("Production"),
},
},
},
},
},
})
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 andExample = new Aws.Budgets.Budget("and_example", new()
{
Name = "budget-and-filter",
BudgetType = "COST",
LimitAmount = "1200",
LimitUnit = "USD",
TimeUnit = "MONTHLY",
FilterExpression = new Aws.Budgets.Inputs.BudgetFilterExpressionArgs
{
Ands = new[]
{
new Aws.Budgets.Inputs.BudgetFilterExpressionAndArgs
{
Dimensions = new Aws.Budgets.Inputs.BudgetFilterExpressionAndDimensionsArgs
{
Key = "SERVICE",
Values = new[]
{
"Amazon Elastic Compute Cloud - Compute",
},
},
},
new Aws.Budgets.Inputs.BudgetFilterExpressionAndArgs
{
Tags = new Aws.Budgets.Inputs.BudgetFilterExpressionAndTagsArgs
{
Key = "Environment",
Values = new[]
{
"Production",
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.budgets.Budget;
import com.pulumi.aws.budgets.BudgetArgs;
import com.pulumi.aws.budgets.inputs.BudgetFilterExpressionArgs;
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 andExample = new Budget("andExample", BudgetArgs.builder()
.name("budget-and-filter")
.budgetType("COST")
.limitAmount("1200")
.limitUnit("USD")
.timeUnit("MONTHLY")
.filterExpression(BudgetFilterExpressionArgs.builder()
.ands(
BudgetFilterExpressionAndArgs.builder()
.dimensions(BudgetFilterExpressionAndDimensionsArgs.builder()
.key("SERVICE")
.values("Amazon Elastic Compute Cloud - Compute")
.build())
.build(),
BudgetFilterExpressionAndArgs.builder()
.tags(BudgetFilterExpressionAndTagsArgs.builder()
.key("Environment")
.values("Production")
.build())
.build())
.build())
.build());
}
}
resources:
andExample:
type: aws:budgets:Budget
name: and_example
properties:
name: budget-and-filter
budgetType: COST
limitAmount: '1200'
limitUnit: USD
timeUnit: MONTHLY
filterExpression:
ands:
- dimensions:
key: SERVICE
values:
- Amazon Elastic Compute Cloud - Compute
- tags:
key: Environment
values:
- Production
The ands array combines multiple filter conditions; all must match for costs to be included. This example tracks only EC2 costs tagged as Production, excluding development and staging environments. Each element in the ands array can use dimensions, tags, or costCategories.
Exclude specific regions with NOT filters
Organizations may want to track costs everywhere except specific regions, such as excluding a region used only for disaster recovery testing.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const notExample = new aws.budgets.Budget("not_example", {
name: "budget-not-filter",
budgetType: "COST",
limitAmount: "1000",
limitUnit: "USD",
timeUnit: "MONTHLY",
filterExpression: {
not: {
dimensions: {
key: "REGION",
values: ["us-west-2"],
},
},
},
});
import pulumi
import pulumi_aws as aws
not_example = aws.budgets.Budget("not_example",
name="budget-not-filter",
budget_type="COST",
limit_amount="1000",
limit_unit="USD",
time_unit="MONTHLY",
filter_expression={
"not_": {
"dimensions": {
"key": "REGION",
"values": ["us-west-2"],
},
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/budgets"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := budgets.NewBudget(ctx, "not_example", &budgets.BudgetArgs{
Name: pulumi.String("budget-not-filter"),
BudgetType: pulumi.String("COST"),
LimitAmount: pulumi.String("1000"),
LimitUnit: pulumi.String("USD"),
TimeUnit: pulumi.String("MONTHLY"),
FilterExpression: &budgets.BudgetFilterExpressionArgs{
Not: &budgets.BudgetFilterExpressionNotArgs{
Dimensions: &budgets.BudgetFilterExpressionNotDimensionsArgs{
Key: pulumi.String("REGION"),
Values: pulumi.StringArray{
pulumi.String("us-west-2"),
},
},
},
},
})
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 notExample = new Aws.Budgets.Budget("not_example", new()
{
Name = "budget-not-filter",
BudgetType = "COST",
LimitAmount = "1000",
LimitUnit = "USD",
TimeUnit = "MONTHLY",
FilterExpression = new Aws.Budgets.Inputs.BudgetFilterExpressionArgs
{
Not = new Aws.Budgets.Inputs.BudgetFilterExpressionNotArgs
{
Dimensions = new Aws.Budgets.Inputs.BudgetFilterExpressionNotDimensionsArgs
{
Key = "REGION",
Values = new[]
{
"us-west-2",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.budgets.Budget;
import com.pulumi.aws.budgets.BudgetArgs;
import com.pulumi.aws.budgets.inputs.BudgetFilterExpressionArgs;
import com.pulumi.aws.budgets.inputs.BudgetFilterExpressionNotArgs;
import com.pulumi.aws.budgets.inputs.BudgetFilterExpressionNotDimensionsArgs;
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 notExample = new Budget("notExample", BudgetArgs.builder()
.name("budget-not-filter")
.budgetType("COST")
.limitAmount("1000")
.limitUnit("USD")
.timeUnit("MONTHLY")
.filterExpression(BudgetFilterExpressionArgs.builder()
.not(BudgetFilterExpressionNotArgs.builder()
.dimensions(BudgetFilterExpressionNotDimensionsArgs.builder()
.key("REGION")
.values("us-west-2")
.build())
.build())
.build())
.build());
}
}
resources:
notExample:
type: aws:budgets:Budget
name: not_example
properties:
name: budget-not-filter
budgetType: COST
limitAmount: '1000'
limitUnit: USD
timeUnit: MONTHLY
filterExpression:
not:
dimensions:
key: REGION
values:
- us-west-2
The not object inverts a filter condition, excluding costs that match the specified criteria. This example tracks costs in all regions except us-west-2. NOT filters work with dimensions, tags, and costCategories, and can be combined with AND and OR logic for complex exclusion patterns.
Beyond these examples
These snippets focus on specific budget-level features: cost and usage budget types, email notifications and threshold alerts, and filter expressions (dimensions, tags, logical operators). They’re intentionally minimal rather than full cost management solutions.
The examples may reference pre-existing infrastructure such as valid email addresses for notifications. They focus on configuring the budget rather than provisioning notification infrastructure.
To keep things focused, common budget patterns are omitted, including:
- Auto-adjusting budgets (autoAdjustData)
- SNS topic notifications (subscriberSnsTopicArns)
- Cost category filters
- Billing view integration (billingViewArn)
These omissions are intentional: the goal is to illustrate how each budget feature is wired, not provide drop-in cost management modules. See the AWS Budget resource reference for all available configuration options.
Let's configure AWS Budgets
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Budget Configuration & Immutability
accountId, name, and namePrefix properties are immutable. Changing them requires recreating the budget.filterExpression for complex logic (AND/OR/NOT operators) or costFilters for simple name/value filtering. The filterExpression approach is newer and more flexible.Budget Types & Limits
Four types are available:
- COST - Track monetary spend (use
limitUnit: "USD") - USAGE - Track resource consumption (use
limitUnit: "GB"or similar) - SAVINGS_PLANS_UTILIZATION - Track Savings Plan usage (use
limitUnit: "PERCENTAGE") - RI_UTILIZATION - Track Reserved Instance usage (use
limitUnit: "PERCENTAGE")
limitAmount and limitUnit for a constant budget. Planned limits use plannedLimits to specify varying amounts over time, with each entry defining a startTime, amount, and unit.MONTHLY, QUARTERLY, ANNUALLY, and DAILY.Filtering & Cost Tracking
costFilters with name: "TagKeyValue" and values in the format TagKey$TagValue. For example: "user:business-unit$human_resources" or "aws:createdBy$Pulumi".filterExpression with ands, ors, and not properties. You can nest these operators to create compound filters combining dimensions, tags, and cost categories.filterExpression with ors to match multiple services, or ands to require multiple conditions. For example, you can filter for EC2 OR RDS costs, or EC2 costs AND Production tag.Time Periods & Notifications
timePeriodStart and timePeriodEnd in format 2017-01-01_12:00. If you don’t specify timePeriodStart, AWS defaults to the start of your chosen time period. There are no restrictions on the end date.notifications property with comparisonOperator, threshold, thresholdType, notificationType, and subscriberEmailAddresses. You can define multiple notifications for different thresholds.Using a different cloud?
Explore monitoring guides for other cloud providers: