The azure-native:costmanagement:Budget resource, part of the Pulumi Azure Native provider, defines cost budgets and reservation utilization alerts at various Azure billing scopes. This guide focuses on three capabilities: cost tracking with filtered notifications, reservation utilization monitoring, and dimension-based filtering for targeted alerts.
Budgets reference existing billing scopes and may trigger Action Groups for notifications. The examples are intentionally small. Combine them with your own billing hierarchy, notification channels, and filtering logic.
Track subscription costs with filtered notifications
Most cost management workflows begin by setting a spending limit and configuring alerts when actual costs approach that threshold.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const budget = new azure_native.costmanagement.Budget("budget", {
amount: 100.65,
budgetName: "TestBudget",
category: azure_native.costmanagement.CategoryType.Cost,
eTag: "\"1d34d016a593709\"",
filter: {
and: [
{
dimensions: {
name: "ResourceId",
operator: azure_native.costmanagement.BudgetOperatorType.In,
values: [
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/MSVM2",
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/platformcloudplatformGeneric1",
],
},
},
{
tags: {
name: "category",
operator: azure_native.costmanagement.BudgetOperatorType.In,
values: [
"Dev",
"Prod",
],
},
},
{
tags: {
name: "department",
operator: azure_native.costmanagement.BudgetOperatorType.In,
values: [
"engineering",
"sales",
],
},
},
],
},
notifications: {
Actual_GreaterThan_80_Percent: {
contactEmails: [
"johndoe@contoso.com",
"janesmith@contoso.com",
],
contactGroups: ["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/microsoft.insights/actionGroups/SampleActionGroup"],
contactRoles: [
"Contributor",
"Reader",
],
enabled: true,
locale: azure_native.costmanagement.CultureCode.En_us,
operator: azure_native.costmanagement.BudgetNotificationOperatorType.GreaterThan,
threshold: 80,
thresholdType: azure_native.costmanagement.ThresholdType.Actual,
},
},
scope: "subscriptions/00000000-0000-0000-0000-000000000000",
timeGrain: azure_native.costmanagement.TimeGrainType.Monthly,
timePeriod: {
endDate: "2024-10-31T00:00:00Z",
startDate: "2023-04-01T00:00:00Z",
},
});
import pulumi
import pulumi_azure_native as azure_native
budget = azure_native.costmanagement.Budget("budget",
amount=100.65,
budget_name="TestBudget",
category=azure_native.costmanagement.CategoryType.COST,
e_tag="\"1d34d016a593709\"",
filter={
"and_": [
{
"dimensions": {
"name": "ResourceId",
"operator": azure_native.costmanagement.BudgetOperatorType.IN_,
"values": [
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/MSVM2",
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/platformcloudplatformGeneric1",
],
},
},
{
"tags": {
"name": "category",
"operator": azure_native.costmanagement.BudgetOperatorType.IN_,
"values": [
"Dev",
"Prod",
],
},
},
{
"tags": {
"name": "department",
"operator": azure_native.costmanagement.BudgetOperatorType.IN_,
"values": [
"engineering",
"sales",
],
},
},
],
},
notifications={
"Actual_GreaterThan_80_Percent": {
"contact_emails": [
"johndoe@contoso.com",
"janesmith@contoso.com",
],
"contact_groups": ["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/microsoft.insights/actionGroups/SampleActionGroup"],
"contact_roles": [
"Contributor",
"Reader",
],
"enabled": True,
"locale": azure_native.costmanagement.CultureCode.EN_US,
"operator": azure_native.costmanagement.BudgetNotificationOperatorType.GREATER_THAN,
"threshold": 80,
"threshold_type": azure_native.costmanagement.ThresholdType.ACTUAL,
},
},
scope="subscriptions/00000000-0000-0000-0000-000000000000",
time_grain=azure_native.costmanagement.TimeGrainType.MONTHLY,
time_period={
"end_date": "2024-10-31T00:00:00Z",
"start_date": "2023-04-01T00:00:00Z",
})
package main
import (
costmanagement "github.com/pulumi/pulumi-azure-native-sdk/costmanagement/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := costmanagement.NewBudget(ctx, "budget", &costmanagement.BudgetArgs{
Amount: pulumi.Float64(100.65),
BudgetName: pulumi.String("TestBudget"),
Category: pulumi.String(costmanagement.CategoryTypeCost),
ETag: pulumi.String("\"1d34d016a593709\""),
Filter: &costmanagement.BudgetFilterArgs{
And: costmanagement.BudgetFilterPropertiesArray{
&costmanagement.BudgetFilterPropertiesArgs{
Dimensions: &costmanagement.BudgetComparisonExpressionArgs{
Name: pulumi.String("ResourceId"),
Operator: pulumi.String(costmanagement.BudgetOperatorTypeIn),
Values: pulumi.StringArray{
pulumi.String("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/MSVM2"),
pulumi.String("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/platformcloudplatformGeneric1"),
},
},
},
&costmanagement.BudgetFilterPropertiesArgs{
Tags: &costmanagement.BudgetComparisonExpressionArgs{
Name: pulumi.String("category"),
Operator: pulumi.String(costmanagement.BudgetOperatorTypeIn),
Values: pulumi.StringArray{
pulumi.String("Dev"),
pulumi.String("Prod"),
},
},
},
&costmanagement.BudgetFilterPropertiesArgs{
Tags: &costmanagement.BudgetComparisonExpressionArgs{
Name: pulumi.String("department"),
Operator: pulumi.String(costmanagement.BudgetOperatorTypeIn),
Values: pulumi.StringArray{
pulumi.String("engineering"),
pulumi.String("sales"),
},
},
},
},
},
Notifications: costmanagement.NotificationMap{
"Actual_GreaterThan_80_Percent": &costmanagement.NotificationArgs{
ContactEmails: pulumi.StringArray{
pulumi.String("johndoe@contoso.com"),
pulumi.String("janesmith@contoso.com"),
},
ContactGroups: pulumi.StringArray{
pulumi.String("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/microsoft.insights/actionGroups/SampleActionGroup"),
},
ContactRoles: pulumi.StringArray{
pulumi.String("Contributor"),
pulumi.String("Reader"),
},
Enabled: pulumi.Bool(true),
Locale: pulumi.String(costmanagement.CultureCode_En_Us),
Operator: pulumi.String(costmanagement.BudgetNotificationOperatorTypeGreaterThan),
Threshold: pulumi.Float64(80),
ThresholdType: pulumi.String(costmanagement.ThresholdTypeActual),
},
},
Scope: pulumi.String("subscriptions/00000000-0000-0000-0000-000000000000"),
TimeGrain: pulumi.String(costmanagement.TimeGrainTypeMonthly),
TimePeriod: &costmanagement.BudgetTimePeriodArgs{
EndDate: pulumi.String("2024-10-31T00:00:00Z"),
StartDate: pulumi.String("2023-04-01T00:00:00Z"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var budget = new AzureNative.CostManagement.Budget("budget", new()
{
Amount = 100.65,
BudgetName = "TestBudget",
Category = AzureNative.CostManagement.CategoryType.Cost,
ETag = "\"1d34d016a593709\"",
Filter = new AzureNative.CostManagement.Inputs.BudgetFilterArgs
{
And = new[]
{
new AzureNative.CostManagement.Inputs.BudgetFilterPropertiesArgs
{
Dimensions = new AzureNative.CostManagement.Inputs.BudgetComparisonExpressionArgs
{
Name = "ResourceId",
Operator = AzureNative.CostManagement.BudgetOperatorType.In,
Values = new[]
{
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/MSVM2",
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/platformcloudplatformGeneric1",
},
},
},
new AzureNative.CostManagement.Inputs.BudgetFilterPropertiesArgs
{
Tags = new AzureNative.CostManagement.Inputs.BudgetComparisonExpressionArgs
{
Name = "category",
Operator = AzureNative.CostManagement.BudgetOperatorType.In,
Values = new[]
{
"Dev",
"Prod",
},
},
},
new AzureNative.CostManagement.Inputs.BudgetFilterPropertiesArgs
{
Tags = new AzureNative.CostManagement.Inputs.BudgetComparisonExpressionArgs
{
Name = "department",
Operator = AzureNative.CostManagement.BudgetOperatorType.In,
Values = new[]
{
"engineering",
"sales",
},
},
},
},
},
Notifications =
{
{ "Actual_GreaterThan_80_Percent", new AzureNative.CostManagement.Inputs.NotificationArgs
{
ContactEmails = new[]
{
"johndoe@contoso.com",
"janesmith@contoso.com",
},
ContactGroups = new[]
{
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/microsoft.insights/actionGroups/SampleActionGroup",
},
ContactRoles = new[]
{
"Contributor",
"Reader",
},
Enabled = true,
Locale = AzureNative.CostManagement.CultureCode.En_us,
Operator = AzureNative.CostManagement.BudgetNotificationOperatorType.GreaterThan,
Threshold = 80,
ThresholdType = AzureNative.CostManagement.ThresholdType.Actual,
} },
},
Scope = "subscriptions/00000000-0000-0000-0000-000000000000",
TimeGrain = AzureNative.CostManagement.TimeGrainType.Monthly,
TimePeriod = new AzureNative.CostManagement.Inputs.BudgetTimePeriodArgs
{
EndDate = "2024-10-31T00:00:00Z",
StartDate = "2023-04-01T00:00:00Z",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.costmanagement.Budget;
import com.pulumi.azurenative.costmanagement.BudgetArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetFilterArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetTimePeriodArgs;
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 budget = new Budget("budget", BudgetArgs.builder()
.amount(100.65)
.budgetName("TestBudget")
.category("Cost")
.eTag("\"1d34d016a593709\"")
.filter(BudgetFilterArgs.builder()
.and(
BudgetFilterPropertiesArgs.builder()
.dimensions(BudgetComparisonExpressionArgs.builder()
.name("ResourceId")
.operator("In")
.values(
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/MSVM2",
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/platformcloudplatformGeneric1")
.build())
.build(),
BudgetFilterPropertiesArgs.builder()
.tags(BudgetComparisonExpressionArgs.builder()
.name("category")
.operator("In")
.values(
"Dev",
"Prod")
.build())
.build(),
BudgetFilterPropertiesArgs.builder()
.tags(BudgetComparisonExpressionArgs.builder()
.name("department")
.operator("In")
.values(
"engineering",
"sales")
.build())
.build())
.build())
.notifications(Map.of("Actual_GreaterThan_80_Percent", NotificationArgs.builder()
.contactEmails(
"johndoe@contoso.com",
"janesmith@contoso.com")
.contactGroups("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/microsoft.insights/actionGroups/SampleActionGroup")
.contactRoles(
"Contributor",
"Reader")
.enabled(true)
.locale("en-us")
.operator("GreaterThan")
.threshold(80.0)
.thresholdType("Actual")
.build()))
.scope("subscriptions/00000000-0000-0000-0000-000000000000")
.timeGrain("Monthly")
.timePeriod(BudgetTimePeriodArgs.builder()
.endDate("2024-10-31T00:00:00Z")
.startDate("2023-04-01T00:00:00Z")
.build())
.build());
}
}
resources:
budget:
type: azure-native:costmanagement:Budget
properties:
amount: 100.65
budgetName: TestBudget
category: Cost
eTag: '"1d34d016a593709"'
filter:
and:
- dimensions:
name: ResourceId
operator: In
values:
- /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/MSVM2
- /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/Microsoft.Compute/virtualMachines/platformcloudplatformGeneric1
- tags:
name: category
operator: In
values:
- Dev
- Prod
- tags:
name: department
operator: In
values:
- engineering
- sales
notifications:
Actual_GreaterThan_80_Percent:
contactEmails:
- johndoe@contoso.com
- janesmith@contoso.com
contactGroups:
- /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MYDEVTESTRG/providers/microsoft.insights/actionGroups/SampleActionGroup
contactRoles:
- Contributor
- Reader
enabled: true
locale: en-us
operator: GreaterThan
threshold: 80
thresholdType: Actual
scope: subscriptions/00000000-0000-0000-0000-000000000000
timeGrain: Monthly
timePeriod:
endDate: 2024-10-31T00:00:00Z
startDate: 2023-04-01T00:00:00Z
When actual spending crosses the threshold percentage, Azure sends notifications to the specified email addresses, Action Groups, and RBAC roles. The filter property narrows the budget scope using dimensions (like ResourceId) and tags (like category or department), allowing you to track specific workloads or cost centers. The timeGrain controls how often the budget resets; Monthly budgets reset on the first of each month. The timePeriod defines when the budget is active.
Monitor reservation utilization across billing account
Organizations with Azure reservations need visibility into whether purchased capacity is being used efficiently.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const budget = new azure_native.costmanagement.Budget("budget", {
budgetName: "TestAlertRule",
category: azure_native.costmanagement.CategoryType.ReservationUtilization,
eTag: "\"1d34d016a593709\"",
filter: {},
notifications: {
Actual_LessThan_99_Percent: {
contactEmails: [
"johndoe@contoso.com",
"janesmith@contoso.com",
],
enabled: true,
frequency: azure_native.costmanagement.Frequency.Weekly,
locale: azure_native.costmanagement.CultureCode.En_us,
operator: azure_native.costmanagement.BudgetNotificationOperatorType.LessThan,
threshold: 99,
},
},
scope: "providers/Microsoft.Billing/billingAccounts/123456",
timeGrain: azure_native.costmanagement.TimeGrainType.Last7Days,
timePeriod: {
endDate: "2025-04-01T00:00:00Z",
startDate: "2023-04-01T00:00:00Z",
},
});
import pulumi
import pulumi_azure_native as azure_native
budget = azure_native.costmanagement.Budget("budget",
budget_name="TestAlertRule",
category=azure_native.costmanagement.CategoryType.RESERVATION_UTILIZATION,
e_tag="\"1d34d016a593709\"",
filter={},
notifications={
"Actual_LessThan_99_Percent": {
"contact_emails": [
"johndoe@contoso.com",
"janesmith@contoso.com",
],
"enabled": True,
"frequency": azure_native.costmanagement.Frequency.WEEKLY,
"locale": azure_native.costmanagement.CultureCode.EN_US,
"operator": azure_native.costmanagement.BudgetNotificationOperatorType.LESS_THAN,
"threshold": 99,
},
},
scope="providers/Microsoft.Billing/billingAccounts/123456",
time_grain=azure_native.costmanagement.TimeGrainType.LAST7_DAYS,
time_period={
"end_date": "2025-04-01T00:00:00Z",
"start_date": "2023-04-01T00:00:00Z",
})
package main
import (
costmanagement "github.com/pulumi/pulumi-azure-native-sdk/costmanagement/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := costmanagement.NewBudget(ctx, "budget", &costmanagement.BudgetArgs{
BudgetName: pulumi.String("TestAlertRule"),
Category: pulumi.String(costmanagement.CategoryTypeReservationUtilization),
ETag: pulumi.String("\"1d34d016a593709\""),
Filter: &costmanagement.BudgetFilterArgs{},
Notifications: costmanagement.NotificationMap{
"Actual_LessThan_99_Percent": &costmanagement.NotificationArgs{
ContactEmails: pulumi.StringArray{
pulumi.String("johndoe@contoso.com"),
pulumi.String("janesmith@contoso.com"),
},
Enabled: pulumi.Bool(true),
Frequency: pulumi.String(costmanagement.FrequencyWeekly),
Locale: pulumi.String(costmanagement.CultureCode_En_Us),
Operator: pulumi.String(costmanagement.BudgetNotificationOperatorTypeLessThan),
Threshold: pulumi.Float64(99),
},
},
Scope: pulumi.String("providers/Microsoft.Billing/billingAccounts/123456"),
TimeGrain: pulumi.String(costmanagement.TimeGrainTypeLast7Days),
TimePeriod: &costmanagement.BudgetTimePeriodArgs{
EndDate: pulumi.String("2025-04-01T00:00:00Z"),
StartDate: pulumi.String("2023-04-01T00:00:00Z"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var budget = new AzureNative.CostManagement.Budget("budget", new()
{
BudgetName = "TestAlertRule",
Category = AzureNative.CostManagement.CategoryType.ReservationUtilization,
ETag = "\"1d34d016a593709\"",
Filter = null,
Notifications =
{
{ "Actual_LessThan_99_Percent", new AzureNative.CostManagement.Inputs.NotificationArgs
{
ContactEmails = new[]
{
"johndoe@contoso.com",
"janesmith@contoso.com",
},
Enabled = true,
Frequency = AzureNative.CostManagement.Frequency.Weekly,
Locale = AzureNative.CostManagement.CultureCode.En_us,
Operator = AzureNative.CostManagement.BudgetNotificationOperatorType.LessThan,
Threshold = 99,
} },
},
Scope = "providers/Microsoft.Billing/billingAccounts/123456",
TimeGrain = AzureNative.CostManagement.TimeGrainType.Last7Days,
TimePeriod = new AzureNative.CostManagement.Inputs.BudgetTimePeriodArgs
{
EndDate = "2025-04-01T00:00:00Z",
StartDate = "2023-04-01T00:00:00Z",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.costmanagement.Budget;
import com.pulumi.azurenative.costmanagement.BudgetArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetFilterArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetTimePeriodArgs;
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 budget = new Budget("budget", BudgetArgs.builder()
.budgetName("TestAlertRule")
.category("ReservationUtilization")
.eTag("\"1d34d016a593709\"")
.filter(BudgetFilterArgs.builder()
.build())
.notifications(Map.of("Actual_LessThan_99_Percent", NotificationArgs.builder()
.contactEmails(
"johndoe@contoso.com",
"janesmith@contoso.com")
.enabled(true)
.frequency("Weekly")
.locale("en-us")
.operator("LessThan")
.threshold(99.0)
.build()))
.scope("providers/Microsoft.Billing/billingAccounts/123456")
.timeGrain("Last7Days")
.timePeriod(BudgetTimePeriodArgs.builder()
.endDate("2025-04-01T00:00:00Z")
.startDate("2023-04-01T00:00:00Z")
.build())
.build());
}
}
resources:
budget:
type: azure-native:costmanagement:Budget
properties:
budgetName: TestAlertRule
category: ReservationUtilization
eTag: '"1d34d016a593709"'
filter: {}
notifications:
Actual_LessThan_99_Percent:
contactEmails:
- johndoe@contoso.com
- janesmith@contoso.com
enabled: true
frequency: Weekly
locale: en-us
operator: LessThan
threshold: 99
scope: providers/Microsoft.Billing/billingAccounts/123456
timeGrain: Last7Days
timePeriod:
endDate: 2025-04-01T00:00:00Z
startDate: 2023-04-01T00:00:00Z
Reservation utilization budgets track usage percentage rather than cost amounts. The category property switches from Cost to ReservationUtilization, and the timeGrain uses Last7Days or Last30Days instead of monthly periods. When utilization falls below the threshold (here, 99%), notifications fire. The frequency property controls how often Azure evaluates the condition; Weekly checks reduce alert fatigue compared to daily checks.
Track specific reservations by ID
When managing multiple reservations, teams often need to monitor specific purchases separately.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const budget = new azure_native.costmanagement.Budget("budget", {
budgetName: "TestAlertRule",
category: azure_native.costmanagement.CategoryType.ReservationUtilization,
eTag: "\"1d34d016a593709\"",
filter: {
dimensions: {
name: "ReservationId",
operator: azure_native.costmanagement.BudgetOperatorType.In,
values: [
"00000000-0000-0000-0000-000000000000",
"00000000-0000-0000-0000-000000000001",
"00000000-0000-0000-0000-000000000002",
],
},
},
notifications: {
Actual_LessThan_99_Percent: {
contactEmails: [
"johndoe@contoso.com",
"janesmith@contoso.com",
],
enabled: true,
frequency: azure_native.costmanagement.Frequency.Weekly,
locale: azure_native.costmanagement.CultureCode.En_us,
operator: azure_native.costmanagement.BudgetNotificationOperatorType.LessThan,
threshold: 99,
},
},
scope: "providers/Microsoft.Billing/billingAccounts/123456",
timeGrain: azure_native.costmanagement.TimeGrainType.Last7Days,
timePeriod: {
endDate: "2025-04-01T00:00:00Z",
startDate: "2023-04-01T00:00:00Z",
},
});
import pulumi
import pulumi_azure_native as azure_native
budget = azure_native.costmanagement.Budget("budget",
budget_name="TestAlertRule",
category=azure_native.costmanagement.CategoryType.RESERVATION_UTILIZATION,
e_tag="\"1d34d016a593709\"",
filter={
"dimensions": {
"name": "ReservationId",
"operator": azure_native.costmanagement.BudgetOperatorType.IN_,
"values": [
"00000000-0000-0000-0000-000000000000",
"00000000-0000-0000-0000-000000000001",
"00000000-0000-0000-0000-000000000002",
],
},
},
notifications={
"Actual_LessThan_99_Percent": {
"contact_emails": [
"johndoe@contoso.com",
"janesmith@contoso.com",
],
"enabled": True,
"frequency": azure_native.costmanagement.Frequency.WEEKLY,
"locale": azure_native.costmanagement.CultureCode.EN_US,
"operator": azure_native.costmanagement.BudgetNotificationOperatorType.LESS_THAN,
"threshold": 99,
},
},
scope="providers/Microsoft.Billing/billingAccounts/123456",
time_grain=azure_native.costmanagement.TimeGrainType.LAST7_DAYS,
time_period={
"end_date": "2025-04-01T00:00:00Z",
"start_date": "2023-04-01T00:00:00Z",
})
package main
import (
costmanagement "github.com/pulumi/pulumi-azure-native-sdk/costmanagement/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := costmanagement.NewBudget(ctx, "budget", &costmanagement.BudgetArgs{
BudgetName: pulumi.String("TestAlertRule"),
Category: pulumi.String(costmanagement.CategoryTypeReservationUtilization),
ETag: pulumi.String("\"1d34d016a593709\""),
Filter: &costmanagement.BudgetFilterArgs{
Dimensions: &costmanagement.BudgetComparisonExpressionArgs{
Name: pulumi.String("ReservationId"),
Operator: pulumi.String(costmanagement.BudgetOperatorTypeIn),
Values: pulumi.StringArray{
pulumi.String("00000000-0000-0000-0000-000000000000"),
pulumi.String("00000000-0000-0000-0000-000000000001"),
pulumi.String("00000000-0000-0000-0000-000000000002"),
},
},
},
Notifications: costmanagement.NotificationMap{
"Actual_LessThan_99_Percent": &costmanagement.NotificationArgs{
ContactEmails: pulumi.StringArray{
pulumi.String("johndoe@contoso.com"),
pulumi.String("janesmith@contoso.com"),
},
Enabled: pulumi.Bool(true),
Frequency: pulumi.String(costmanagement.FrequencyWeekly),
Locale: pulumi.String(costmanagement.CultureCode_En_Us),
Operator: pulumi.String(costmanagement.BudgetNotificationOperatorTypeLessThan),
Threshold: pulumi.Float64(99),
},
},
Scope: pulumi.String("providers/Microsoft.Billing/billingAccounts/123456"),
TimeGrain: pulumi.String(costmanagement.TimeGrainTypeLast7Days),
TimePeriod: &costmanagement.BudgetTimePeriodArgs{
EndDate: pulumi.String("2025-04-01T00:00:00Z"),
StartDate: pulumi.String("2023-04-01T00:00:00Z"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var budget = new AzureNative.CostManagement.Budget("budget", new()
{
BudgetName = "TestAlertRule",
Category = AzureNative.CostManagement.CategoryType.ReservationUtilization,
ETag = "\"1d34d016a593709\"",
Filter = new AzureNative.CostManagement.Inputs.BudgetFilterArgs
{
Dimensions = new AzureNative.CostManagement.Inputs.BudgetComparisonExpressionArgs
{
Name = "ReservationId",
Operator = AzureNative.CostManagement.BudgetOperatorType.In,
Values = new[]
{
"00000000-0000-0000-0000-000000000000",
"00000000-0000-0000-0000-000000000001",
"00000000-0000-0000-0000-000000000002",
},
},
},
Notifications =
{
{ "Actual_LessThan_99_Percent", new AzureNative.CostManagement.Inputs.NotificationArgs
{
ContactEmails = new[]
{
"johndoe@contoso.com",
"janesmith@contoso.com",
},
Enabled = true,
Frequency = AzureNative.CostManagement.Frequency.Weekly,
Locale = AzureNative.CostManagement.CultureCode.En_us,
Operator = AzureNative.CostManagement.BudgetNotificationOperatorType.LessThan,
Threshold = 99,
} },
},
Scope = "providers/Microsoft.Billing/billingAccounts/123456",
TimeGrain = AzureNative.CostManagement.TimeGrainType.Last7Days,
TimePeriod = new AzureNative.CostManagement.Inputs.BudgetTimePeriodArgs
{
EndDate = "2025-04-01T00:00:00Z",
StartDate = "2023-04-01T00:00:00Z",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.costmanagement.Budget;
import com.pulumi.azurenative.costmanagement.BudgetArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetFilterArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetComparisonExpressionArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetTimePeriodArgs;
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 budget = new Budget("budget", BudgetArgs.builder()
.budgetName("TestAlertRule")
.category("ReservationUtilization")
.eTag("\"1d34d016a593709\"")
.filter(BudgetFilterArgs.builder()
.dimensions(BudgetComparisonExpressionArgs.builder()
.name("ReservationId")
.operator("In")
.values(
"00000000-0000-0000-0000-000000000000",
"00000000-0000-0000-0000-000000000001",
"00000000-0000-0000-0000-000000000002")
.build())
.build())
.notifications(Map.of("Actual_LessThan_99_Percent", NotificationArgs.builder()
.contactEmails(
"johndoe@contoso.com",
"janesmith@contoso.com")
.enabled(true)
.frequency("Weekly")
.locale("en-us")
.operator("LessThan")
.threshold(99.0)
.build()))
.scope("providers/Microsoft.Billing/billingAccounts/123456")
.timeGrain("Last7Days")
.timePeriod(BudgetTimePeriodArgs.builder()
.endDate("2025-04-01T00:00:00Z")
.startDate("2023-04-01T00:00:00Z")
.build())
.build());
}
}
resources:
budget:
type: azure-native:costmanagement:Budget
properties:
budgetName: TestAlertRule
category: ReservationUtilization
eTag: '"1d34d016a593709"'
filter:
dimensions:
name: ReservationId
operator: In
values:
- 00000000-0000-0000-0000-000000000000
- 00000000-0000-0000-0000-000000000001
- 00000000-0000-0000-0000-000000000002
notifications:
Actual_LessThan_99_Percent:
contactEmails:
- johndoe@contoso.com
- janesmith@contoso.com
enabled: true
frequency: Weekly
locale: en-us
operator: LessThan
threshold: 99
scope: providers/Microsoft.Billing/billingAccounts/123456
timeGrain: Last7Days
timePeriod:
endDate: 2025-04-01T00:00:00Z
startDate: 2023-04-01T00:00:00Z
The filter dimensions property accepts ReservationId to target specific reservation purchases. The operator In allows you to list multiple reservation IDs in the values array. This configuration monitors three reservations independently of others in the billing account. Each reservation’s utilization is evaluated separately; if any falls below 99%, the alert triggers.
Filter reservations by resource type
Different reservation types often have different utilization patterns and business priorities.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const budget = new azure_native.costmanagement.Budget("budget", {
budgetName: "TestAlertRule",
category: azure_native.costmanagement.CategoryType.ReservationUtilization,
eTag: "\"1d34d016a593709\"",
filter: {
dimensions: {
name: "ReservedResourceType",
operator: azure_native.costmanagement.BudgetOperatorType.In,
values: [
"VirtualMachines",
"SqlDatabases",
"CosmosDb",
],
},
},
notifications: {
Actual_LessThan_99_Percent: {
contactEmails: [
"johndoe@contoso.com",
"janesmith@contoso.com",
],
enabled: true,
frequency: azure_native.costmanagement.Frequency.Weekly,
locale: azure_native.costmanagement.CultureCode.En_us,
operator: azure_native.costmanagement.BudgetNotificationOperatorType.LessThan,
threshold: 99,
},
},
scope: "providers/Microsoft.Billing/billingAccounts/123456",
timeGrain: azure_native.costmanagement.TimeGrainType.Last7Days,
timePeriod: {
endDate: "2025-04-01T00:00:00Z",
startDate: "2023-04-01T00:00:00Z",
},
});
import pulumi
import pulumi_azure_native as azure_native
budget = azure_native.costmanagement.Budget("budget",
budget_name="TestAlertRule",
category=azure_native.costmanagement.CategoryType.RESERVATION_UTILIZATION,
e_tag="\"1d34d016a593709\"",
filter={
"dimensions": {
"name": "ReservedResourceType",
"operator": azure_native.costmanagement.BudgetOperatorType.IN_,
"values": [
"VirtualMachines",
"SqlDatabases",
"CosmosDb",
],
},
},
notifications={
"Actual_LessThan_99_Percent": {
"contact_emails": [
"johndoe@contoso.com",
"janesmith@contoso.com",
],
"enabled": True,
"frequency": azure_native.costmanagement.Frequency.WEEKLY,
"locale": azure_native.costmanagement.CultureCode.EN_US,
"operator": azure_native.costmanagement.BudgetNotificationOperatorType.LESS_THAN,
"threshold": 99,
},
},
scope="providers/Microsoft.Billing/billingAccounts/123456",
time_grain=azure_native.costmanagement.TimeGrainType.LAST7_DAYS,
time_period={
"end_date": "2025-04-01T00:00:00Z",
"start_date": "2023-04-01T00:00:00Z",
})
package main
import (
costmanagement "github.com/pulumi/pulumi-azure-native-sdk/costmanagement/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := costmanagement.NewBudget(ctx, "budget", &costmanagement.BudgetArgs{
BudgetName: pulumi.String("TestAlertRule"),
Category: pulumi.String(costmanagement.CategoryTypeReservationUtilization),
ETag: pulumi.String("\"1d34d016a593709\""),
Filter: &costmanagement.BudgetFilterArgs{
Dimensions: &costmanagement.BudgetComparisonExpressionArgs{
Name: pulumi.String("ReservedResourceType"),
Operator: pulumi.String(costmanagement.BudgetOperatorTypeIn),
Values: pulumi.StringArray{
pulumi.String("VirtualMachines"),
pulumi.String("SqlDatabases"),
pulumi.String("CosmosDb"),
},
},
},
Notifications: costmanagement.NotificationMap{
"Actual_LessThan_99_Percent": &costmanagement.NotificationArgs{
ContactEmails: pulumi.StringArray{
pulumi.String("johndoe@contoso.com"),
pulumi.String("janesmith@contoso.com"),
},
Enabled: pulumi.Bool(true),
Frequency: pulumi.String(costmanagement.FrequencyWeekly),
Locale: pulumi.String(costmanagement.CultureCode_En_Us),
Operator: pulumi.String(costmanagement.BudgetNotificationOperatorTypeLessThan),
Threshold: pulumi.Float64(99),
},
},
Scope: pulumi.String("providers/Microsoft.Billing/billingAccounts/123456"),
TimeGrain: pulumi.String(costmanagement.TimeGrainTypeLast7Days),
TimePeriod: &costmanagement.BudgetTimePeriodArgs{
EndDate: pulumi.String("2025-04-01T00:00:00Z"),
StartDate: pulumi.String("2023-04-01T00:00:00Z"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var budget = new AzureNative.CostManagement.Budget("budget", new()
{
BudgetName = "TestAlertRule",
Category = AzureNative.CostManagement.CategoryType.ReservationUtilization,
ETag = "\"1d34d016a593709\"",
Filter = new AzureNative.CostManagement.Inputs.BudgetFilterArgs
{
Dimensions = new AzureNative.CostManagement.Inputs.BudgetComparisonExpressionArgs
{
Name = "ReservedResourceType",
Operator = AzureNative.CostManagement.BudgetOperatorType.In,
Values = new[]
{
"VirtualMachines",
"SqlDatabases",
"CosmosDb",
},
},
},
Notifications =
{
{ "Actual_LessThan_99_Percent", new AzureNative.CostManagement.Inputs.NotificationArgs
{
ContactEmails = new[]
{
"johndoe@contoso.com",
"janesmith@contoso.com",
},
Enabled = true,
Frequency = AzureNative.CostManagement.Frequency.Weekly,
Locale = AzureNative.CostManagement.CultureCode.En_us,
Operator = AzureNative.CostManagement.BudgetNotificationOperatorType.LessThan,
Threshold = 99,
} },
},
Scope = "providers/Microsoft.Billing/billingAccounts/123456",
TimeGrain = AzureNative.CostManagement.TimeGrainType.Last7Days,
TimePeriod = new AzureNative.CostManagement.Inputs.BudgetTimePeriodArgs
{
EndDate = "2025-04-01T00:00:00Z",
StartDate = "2023-04-01T00:00:00Z",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.costmanagement.Budget;
import com.pulumi.azurenative.costmanagement.BudgetArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetFilterArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetComparisonExpressionArgs;
import com.pulumi.azurenative.costmanagement.inputs.BudgetTimePeriodArgs;
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 budget = new Budget("budget", BudgetArgs.builder()
.budgetName("TestAlertRule")
.category("ReservationUtilization")
.eTag("\"1d34d016a593709\"")
.filter(BudgetFilterArgs.builder()
.dimensions(BudgetComparisonExpressionArgs.builder()
.name("ReservedResourceType")
.operator("In")
.values(
"VirtualMachines",
"SqlDatabases",
"CosmosDb")
.build())
.build())
.notifications(Map.of("Actual_LessThan_99_Percent", NotificationArgs.builder()
.contactEmails(
"johndoe@contoso.com",
"janesmith@contoso.com")
.enabled(true)
.frequency("Weekly")
.locale("en-us")
.operator("LessThan")
.threshold(99.0)
.build()))
.scope("providers/Microsoft.Billing/billingAccounts/123456")
.timeGrain("Last7Days")
.timePeriod(BudgetTimePeriodArgs.builder()
.endDate("2025-04-01T00:00:00Z")
.startDate("2023-04-01T00:00:00Z")
.build())
.build());
}
}
resources:
budget:
type: azure-native:costmanagement:Budget
properties:
budgetName: TestAlertRule
category: ReservationUtilization
eTag: '"1d34d016a593709"'
filter:
dimensions:
name: ReservedResourceType
operator: In
values:
- VirtualMachines
- SqlDatabases
- CosmosDb
notifications:
Actual_LessThan_99_Percent:
contactEmails:
- johndoe@contoso.com
- janesmith@contoso.com
enabled: true
frequency: Weekly
locale: en-us
operator: LessThan
threshold: 99
scope: providers/Microsoft.Billing/billingAccounts/123456
timeGrain: Last7Days
timePeriod:
endDate: 2025-04-01T00:00:00Z
startDate: 2023-04-01T00:00:00Z
Instead of filtering by reservation ID, you can filter by ReservedResourceType to monitor all reservations of a given type. This example tracks VirtualMachines, SqlDatabases, and CosmosDb reservations together. When any reservation of these types drops below 99% utilization, the alert fires. This approach works well when you care about resource type utilization trends rather than individual reservation performance.
Beyond these examples
These snippets focus on specific budget-level features: cost budgets with resource and tag filtering, reservation utilization alerts, and dimension-based filtering. They’re intentionally minimal rather than full cost management solutions.
The examples may reference pre-existing infrastructure such as Azure subscriptions, billing accounts, billing profiles, or customer scopes, Action Groups for notification delivery, and active reservations for utilization monitoring. They focus on configuring the budget rather than provisioning the billing hierarchy around it.
To keep things focused, common budget patterns are omitted, including:
- Forecast-based notifications (thresholdType: Forecasted)
- Multiple notification thresholds per budget
- Management group and department scopes
- Tag-based filtering beyond the basic example
- Billing period time grains (BillingMonth, BillingQuarter, BillingAnnual)
These omissions are intentional: the goal is to illustrate how each budget feature is wired, not provide drop-in cost management modules. See the Budget resource reference for all available configuration options.
Let's configure Azure Cost Management Budgets
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Budget Types & Categories
amount and support multiple notification thresholds. ReservationUtilization alerts monitor reservation usage without an amount limit and support only one notification.amount property is required for Cost budgets but not applicable for ReservationUtilization alerts.Notifications & Alerts
thresholdType: Actual and 5 with thresholdType: Forecasted. ReservationUtilization alerts support only 1 notification, and thresholdType is not applicable.notifications dictionary with entries containing threshold, operator (GreaterThan or LessThan), contactEmails, and optionally contactGroups, contactRoles, enabled, frequency, and locale.thresholdType to Forecasted in your notification configuration. You can have up to 5 forecasted notifications.Filtering & Scoping
filter property with dimensions to filter by ResourceId, or use tags to filter by tag name and values. You can combine multiple filters using the and array.filter.dimensions.name to ReservationId with an array of reservation IDs, or use ReservedResourceType with values like VirtualMachines, SqlDatabases, or CosmosDb.Time Configuration & Limitations
eTag handles concurrent update scenarios by determining whether you’re updating the latest version of the budget resource.timePeriod with startDate and endDate in ISO 8601 format. The budget evaluates data on or after the startDate and expires on the endDate.