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 Configuration
amount property. ReservationUtilization budgets monitor reservation usage percentages and don’t use the amount property. They also have different time grain options and notification limits.amount property is required for Cost budgets because they track spending against a monetary limit. ReservationUtilization budgets monitor usage percentages instead, so they don’t need an amount.scope property is immutable and cannot be changed after budget creation. Choose your scope carefully (subscription, resource group, billing account, etc.) before creating the budget.eTag field handles concurrent update scenarios by determining whether you’re updating the latest version of the budget. It prevents conflicts when multiple users modify the same budget.Notifications & Alerts
thresholdType: Actual and 5 with thresholdType: Forecasted (10 total). ReservationUtilization budgets support only 1 notification, and thresholdType doesn’t apply.contactEmails for email addresses, contactRoles for Azure RBAC roles (like Contributor or Reader), and contactGroups for Azure Monitor action groups. You can combine all three in a single notification.Filtering & Scoping
filter property with dimensions. For resources, use ResourceId with operator In and a list of resource IDs. For reservations, use ReservationId or ReservedResourceType (like VirtualMachines, SqlDatabases, CosmosDb).and array within the filter property to combine multiple dimension and tag filters. Each filter can target different dimensions or tags.