Configure GCP Billing Budgets

The gcp:billing/budget:Budget resource, part of the Pulumi GCP provider, defines billing budgets that track spending against limits and trigger alerts when thresholds are crossed. This guide focuses on three capabilities: fixed and relative budget amounts, spending filters by project and service, and notification routing with custom date ranges.

Budgets require a billing account ID and may reference project numbers, service IDs, or monitoring notification channels. The examples are intentionally small. Combine them with your own billing accounts, projects, and notification infrastructure.

Set a fixed spending limit with threshold alerts

Most billing budgets start by defining a fixed dollar amount and alerting when spending crosses percentage thresholds.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const account = gcp.organizations.getBillingAccount({
    billingAccount: "000000-0000000-0000000-000000",
});
const budget = new gcp.billing.Budget("budget", {
    billingAccount: account.then(account => account.id),
    displayName: "Example Billing Budget",
    amount: {
        specifiedAmount: {
            currencyCode: "USD",
            units: "100000",
        },
    },
    thresholdRules: [{
        thresholdPercent: 0.5,
    }],
});
import pulumi
import pulumi_gcp as gcp

account = gcp.organizations.get_billing_account(billing_account="000000-0000000-0000000-000000")
budget = gcp.billing.Budget("budget",
    billing_account=account.id,
    display_name="Example Billing Budget",
    amount={
        "specified_amount": {
            "currency_code": "USD",
            "units": "100000",
        },
    },
    threshold_rules=[{
        "threshold_percent": 0.5,
    }])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/billing"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		account, err := organizations.GetBillingAccount(ctx, &organizations.GetBillingAccountArgs{
			BillingAccount: pulumi.StringRef("000000-0000000-0000000-000000"),
		}, nil)
		if err != nil {
			return err
		}
		_, err = billing.NewBudget(ctx, "budget", &billing.BudgetArgs{
			BillingAccount: pulumi.String(account.Id),
			DisplayName:    pulumi.String("Example Billing Budget"),
			Amount: &billing.BudgetAmountArgs{
				SpecifiedAmount: &billing.BudgetAmountSpecifiedAmountArgs{
					CurrencyCode: pulumi.String("USD"),
					Units:        pulumi.String("100000"),
				},
			},
			ThresholdRules: billing.BudgetThresholdRuleArray{
				&billing.BudgetThresholdRuleArgs{
					ThresholdPercent: pulumi.Float64(0.5),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var account = Gcp.Organizations.GetBillingAccount.Invoke(new()
    {
        BillingAccount = "000000-0000000-0000000-000000",
    });

    var budget = new Gcp.Billing.Budget("budget", new()
    {
        BillingAccount = account.Apply(getBillingAccountResult => getBillingAccountResult.Id),
        DisplayName = "Example Billing Budget",
        Amount = new Gcp.Billing.Inputs.BudgetAmountArgs
        {
            SpecifiedAmount = new Gcp.Billing.Inputs.BudgetAmountSpecifiedAmountArgs
            {
                CurrencyCode = "USD",
                Units = "100000",
            },
        },
        ThresholdRules = new[]
        {
            new Gcp.Billing.Inputs.BudgetThresholdRuleArgs
            {
                ThresholdPercent = 0.5,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetBillingAccountArgs;
import com.pulumi.gcp.billing.Budget;
import com.pulumi.gcp.billing.BudgetArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountSpecifiedAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetThresholdRuleArgs;
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) {
        final var account = OrganizationsFunctions.getBillingAccount(GetBillingAccountArgs.builder()
            .billingAccount("000000-0000000-0000000-000000")
            .build());

        var budget = new Budget("budget", BudgetArgs.builder()
            .billingAccount(account.id())
            .displayName("Example Billing Budget")
            .amount(BudgetAmountArgs.builder()
                .specifiedAmount(BudgetAmountSpecifiedAmountArgs.builder()
                    .currencyCode("USD")
                    .units("100000")
                    .build())
                .build())
            .thresholdRules(BudgetThresholdRuleArgs.builder()
                .thresholdPercent(0.5)
                .build())
            .build());

    }
}
resources:
  budget:
    type: gcp:billing:Budget
    properties:
      billingAccount: ${account.id}
      displayName: Example Billing Budget
      amount:
        specifiedAmount:
          currencyCode: USD
          units: '100000'
      thresholdRules:
        - thresholdPercent: 0.5
variables:
  account:
    fn::invoke:
      function: gcp:organizations:getBillingAccount
      arguments:
        billingAccount: 000000-0000000-0000000-000000

When actual spending reaches the threshold percentage, the budget triggers an alert. The amount property sets a fixed limit using specifiedAmount with a currency code and units (in this case, $100,000 USD). The thresholdRules array defines one or more percentage thresholds; here, an alert fires at 50% of the budget.

Track spending relative to the previous period

Teams with predictable monthly costs often budget based on the previous period’s spending rather than a fixed amount.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const account = gcp.organizations.getBillingAccount({
    billingAccount: "000000-0000000-0000000-000000",
});
const project = gcp.organizations.getProject({});
const budget = new gcp.billing.Budget("budget", {
    billingAccount: account.then(account => account.id),
    displayName: "Example Billing Budget",
    budgetFilter: {
        projects: [project.then(project => `projects/${project.number}`)],
    },
    amount: {
        lastPeriodAmount: true,
    },
    thresholdRules: [{
        thresholdPercent: 10,
    }],
});
import pulumi
import pulumi_gcp as gcp

account = gcp.organizations.get_billing_account(billing_account="000000-0000000-0000000-000000")
project = gcp.organizations.get_project()
budget = gcp.billing.Budget("budget",
    billing_account=account.id,
    display_name="Example Billing Budget",
    budget_filter={
        "projects": [f"projects/{project.number}"],
    },
    amount={
        "last_period_amount": True,
    },
    threshold_rules=[{
        "threshold_percent": 10,
    }])
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/billing"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		account, err := organizations.GetBillingAccount(ctx, &organizations.GetBillingAccountArgs{
			BillingAccount: pulumi.StringRef("000000-0000000-0000000-000000"),
		}, nil)
		if err != nil {
			return err
		}
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		_, err = billing.NewBudget(ctx, "budget", &billing.BudgetArgs{
			BillingAccount: pulumi.String(account.Id),
			DisplayName:    pulumi.String("Example Billing Budget"),
			BudgetFilter: &billing.BudgetBudgetFilterArgs{
				Projects: pulumi.StringArray{
					pulumi.Sprintf("projects/%v", project.Number),
				},
			},
			Amount: &billing.BudgetAmountArgs{
				LastPeriodAmount: pulumi.Bool(true),
			},
			ThresholdRules: billing.BudgetThresholdRuleArray{
				&billing.BudgetThresholdRuleArgs{
					ThresholdPercent: pulumi.Float64(10),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var account = Gcp.Organizations.GetBillingAccount.Invoke(new()
    {
        BillingAccount = "000000-0000000-0000000-000000",
    });

    var project = Gcp.Organizations.GetProject.Invoke();

    var budget = new Gcp.Billing.Budget("budget", new()
    {
        BillingAccount = account.Apply(getBillingAccountResult => getBillingAccountResult.Id),
        DisplayName = "Example Billing Budget",
        BudgetFilter = new Gcp.Billing.Inputs.BudgetBudgetFilterArgs
        {
            Projects = new[]
            {
                $"projects/{project.Apply(getProjectResult => getProjectResult.Number)}",
            },
        },
        Amount = new Gcp.Billing.Inputs.BudgetAmountArgs
        {
            LastPeriodAmount = true,
        },
        ThresholdRules = new[]
        {
            new Gcp.Billing.Inputs.BudgetThresholdRuleArgs
            {
                ThresholdPercent = 10,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetBillingAccountArgs;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.billing.Budget;
import com.pulumi.gcp.billing.BudgetArgs;
import com.pulumi.gcp.billing.inputs.BudgetBudgetFilterArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetThresholdRuleArgs;
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) {
        final var account = OrganizationsFunctions.getBillingAccount(GetBillingAccountArgs.builder()
            .billingAccount("000000-0000000-0000000-000000")
            .build());

        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var budget = new Budget("budget", BudgetArgs.builder()
            .billingAccount(account.id())
            .displayName("Example Billing Budget")
            .budgetFilter(BudgetBudgetFilterArgs.builder()
                .projects(String.format("projects/%s", project.number()))
                .build())
            .amount(BudgetAmountArgs.builder()
                .lastPeriodAmount(true)
                .build())
            .thresholdRules(BudgetThresholdRuleArgs.builder()
                .thresholdPercent(10.0)
                .build())
            .build());

    }
}
resources:
  budget:
    type: gcp:billing:Budget
    properties:
      billingAccount: ${account.id}
      displayName: Example Billing Budget
      budgetFilter:
        projects:
          - projects/${project.number}
      amount:
        lastPeriodAmount: true
      thresholdRules:
        - thresholdPercent: 10
variables:
  account:
    fn::invoke:
      function: gcp:organizations:getBillingAccount
      arguments:
        billingAccount: 000000-0000000-0000000-000000
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

Setting lastPeriodAmount to true makes the budget track spending relative to the previous billing period’s total. The budgetFilter property scopes the budget to specific projects using their project numbers. This configuration alerts when current spending exceeds 10% of last period’s total for the filtered projects.

Filter spending by projects, services, and credits

Organizations tracking costs for specific workloads need to filter budgets by project, service, or credit type.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const account = gcp.organizations.getBillingAccount({
    billingAccount: "000000-0000000-0000000-000000",
});
const project = gcp.organizations.getProject({});
const budget = new gcp.billing.Budget("budget", {
    billingAccount: account.then(account => account.id),
    displayName: "Example Billing Budget",
    budgetFilter: {
        projects: [project.then(project => `projects/${project.number}`)],
        creditTypesTreatment: "INCLUDE_SPECIFIED_CREDITS",
        services: ["services/24E6-581D-38E5"],
        creditTypes: [
            "PROMOTION",
            "FREE_TIER",
        ],
        resourceAncestors: ["organizations/123456789"],
    },
    amount: {
        specifiedAmount: {
            currencyCode: "USD",
            units: "100000",
        },
    },
    thresholdRules: [
        {
            thresholdPercent: 0.5,
        },
        {
            thresholdPercent: 0.9,
            spendBasis: "FORECASTED_SPEND",
        },
    ],
});
import pulumi
import pulumi_gcp as gcp

account = gcp.organizations.get_billing_account(billing_account="000000-0000000-0000000-000000")
project = gcp.organizations.get_project()
budget = gcp.billing.Budget("budget",
    billing_account=account.id,
    display_name="Example Billing Budget",
    budget_filter={
        "projects": [f"projects/{project.number}"],
        "credit_types_treatment": "INCLUDE_SPECIFIED_CREDITS",
        "services": ["services/24E6-581D-38E5"],
        "credit_types": [
            "PROMOTION",
            "FREE_TIER",
        ],
        "resource_ancestors": ["organizations/123456789"],
    },
    amount={
        "specified_amount": {
            "currency_code": "USD",
            "units": "100000",
        },
    },
    threshold_rules=[
        {
            "threshold_percent": 0.5,
        },
        {
            "threshold_percent": 0.9,
            "spend_basis": "FORECASTED_SPEND",
        },
    ])
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/billing"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		account, err := organizations.GetBillingAccount(ctx, &organizations.GetBillingAccountArgs{
			BillingAccount: pulumi.StringRef("000000-0000000-0000000-000000"),
		}, nil)
		if err != nil {
			return err
		}
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		_, err = billing.NewBudget(ctx, "budget", &billing.BudgetArgs{
			BillingAccount: pulumi.String(account.Id),
			DisplayName:    pulumi.String("Example Billing Budget"),
			BudgetFilter: &billing.BudgetBudgetFilterArgs{
				Projects: pulumi.StringArray{
					pulumi.Sprintf("projects/%v", project.Number),
				},
				CreditTypesTreatment: pulumi.String("INCLUDE_SPECIFIED_CREDITS"),
				Services: pulumi.StringArray{
					pulumi.String("services/24E6-581D-38E5"),
				},
				CreditTypes: pulumi.StringArray{
					pulumi.String("PROMOTION"),
					pulumi.String("FREE_TIER"),
				},
				ResourceAncestors: pulumi.StringArray{
					pulumi.String("organizations/123456789"),
				},
			},
			Amount: &billing.BudgetAmountArgs{
				SpecifiedAmount: &billing.BudgetAmountSpecifiedAmountArgs{
					CurrencyCode: pulumi.String("USD"),
					Units:        pulumi.String("100000"),
				},
			},
			ThresholdRules: billing.BudgetThresholdRuleArray{
				&billing.BudgetThresholdRuleArgs{
					ThresholdPercent: pulumi.Float64(0.5),
				},
				&billing.BudgetThresholdRuleArgs{
					ThresholdPercent: pulumi.Float64(0.9),
					SpendBasis:       pulumi.String("FORECASTED_SPEND"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var account = Gcp.Organizations.GetBillingAccount.Invoke(new()
    {
        BillingAccount = "000000-0000000-0000000-000000",
    });

    var project = Gcp.Organizations.GetProject.Invoke();

    var budget = new Gcp.Billing.Budget("budget", new()
    {
        BillingAccount = account.Apply(getBillingAccountResult => getBillingAccountResult.Id),
        DisplayName = "Example Billing Budget",
        BudgetFilter = new Gcp.Billing.Inputs.BudgetBudgetFilterArgs
        {
            Projects = new[]
            {
                $"projects/{project.Apply(getProjectResult => getProjectResult.Number)}",
            },
            CreditTypesTreatment = "INCLUDE_SPECIFIED_CREDITS",
            Services = new[]
            {
                "services/24E6-581D-38E5",
            },
            CreditTypes = new[]
            {
                "PROMOTION",
                "FREE_TIER",
            },
            ResourceAncestors = new[]
            {
                "organizations/123456789",
            },
        },
        Amount = new Gcp.Billing.Inputs.BudgetAmountArgs
        {
            SpecifiedAmount = new Gcp.Billing.Inputs.BudgetAmountSpecifiedAmountArgs
            {
                CurrencyCode = "USD",
                Units = "100000",
            },
        },
        ThresholdRules = new[]
        {
            new Gcp.Billing.Inputs.BudgetThresholdRuleArgs
            {
                ThresholdPercent = 0.5,
            },
            new Gcp.Billing.Inputs.BudgetThresholdRuleArgs
            {
                ThresholdPercent = 0.9,
                SpendBasis = "FORECASTED_SPEND",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetBillingAccountArgs;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.billing.Budget;
import com.pulumi.gcp.billing.BudgetArgs;
import com.pulumi.gcp.billing.inputs.BudgetBudgetFilterArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountSpecifiedAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetThresholdRuleArgs;
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) {
        final var account = OrganizationsFunctions.getBillingAccount(GetBillingAccountArgs.builder()
            .billingAccount("000000-0000000-0000000-000000")
            .build());

        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var budget = new Budget("budget", BudgetArgs.builder()
            .billingAccount(account.id())
            .displayName("Example Billing Budget")
            .budgetFilter(BudgetBudgetFilterArgs.builder()
                .projects(String.format("projects/%s", project.number()))
                .creditTypesTreatment("INCLUDE_SPECIFIED_CREDITS")
                .services("services/24E6-581D-38E5")
                .creditTypes(                
                    "PROMOTION",
                    "FREE_TIER")
                .resourceAncestors("organizations/123456789")
                .build())
            .amount(BudgetAmountArgs.builder()
                .specifiedAmount(BudgetAmountSpecifiedAmountArgs.builder()
                    .currencyCode("USD")
                    .units("100000")
                    .build())
                .build())
            .thresholdRules(            
                BudgetThresholdRuleArgs.builder()
                    .thresholdPercent(0.5)
                    .build(),
                BudgetThresholdRuleArgs.builder()
                    .thresholdPercent(0.9)
                    .spendBasis("FORECASTED_SPEND")
                    .build())
            .build());

    }
}
resources:
  budget:
    type: gcp:billing:Budget
    properties:
      billingAccount: ${account.id}
      displayName: Example Billing Budget
      budgetFilter:
        projects:
          - projects/${project.number}
        creditTypesTreatment: INCLUDE_SPECIFIED_CREDITS
        services:
          - services/24E6-581D-38E5
        creditTypes:
          - PROMOTION
          - FREE_TIER
        resourceAncestors:
          - organizations/123456789
      amount:
        specifiedAmount:
          currencyCode: USD
          units: '100000'
      thresholdRules:
        - thresholdPercent: 0.5
        - thresholdPercent: 0.9
          spendBasis: FORECASTED_SPEND
variables:
  account:
    fn::invoke:
      function: gcp:organizations:getBillingAccount
      arguments:
        billingAccount: 000000-0000000-0000000-000000
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The budgetFilter property controls which spending counts toward the budget. The projects array limits tracking to specific project numbers. The services array filters to particular GCP services (here, Compute Engine). The creditTypes and creditTypesTreatment properties determine whether promotional credits and free tier usage count toward the budget. The resourceAncestors property can scope budgets to entire organizations or folders.

Send alerts to monitoring notification channels

Budget alerts become actionable when routed to notification channels that reach the right teams.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const account = gcp.organizations.getBillingAccount({
    billingAccount: "000000-0000000-0000000-000000",
});
const project = gcp.organizations.getProject({});
const notificationChannel = new gcp.monitoring.NotificationChannel("notification_channel", {
    displayName: "Example Notification Channel",
    type: "email",
    labels: {
        email_address: "address@example.com",
    },
});
const budget = new gcp.billing.Budget("budget", {
    billingAccount: account.then(account => account.id),
    displayName: "Example Billing Budget",
    budgetFilter: {
        projects: [project.then(project => `projects/${project.number}`)],
    },
    amount: {
        specifiedAmount: {
            currencyCode: "USD",
            units: "100000",
        },
    },
    thresholdRules: [
        {
            thresholdPercent: 1,
        },
        {
            thresholdPercent: 1,
            spendBasis: "FORECASTED_SPEND",
        },
    ],
    allUpdatesRule: {
        monitoringNotificationChannels: [notificationChannel.id],
        disableDefaultIamRecipients: true,
    },
});
import pulumi
import pulumi_gcp as gcp

account = gcp.organizations.get_billing_account(billing_account="000000-0000000-0000000-000000")
project = gcp.organizations.get_project()
notification_channel = gcp.monitoring.NotificationChannel("notification_channel",
    display_name="Example Notification Channel",
    type="email",
    labels={
        "email_address": "address@example.com",
    })
budget = gcp.billing.Budget("budget",
    billing_account=account.id,
    display_name="Example Billing Budget",
    budget_filter={
        "projects": [f"projects/{project.number}"],
    },
    amount={
        "specified_amount": {
            "currency_code": "USD",
            "units": "100000",
        },
    },
    threshold_rules=[
        {
            "threshold_percent": 1,
        },
        {
            "threshold_percent": 1,
            "spend_basis": "FORECASTED_SPEND",
        },
    ],
    all_updates_rule={
        "monitoring_notification_channels": [notification_channel.id],
        "disable_default_iam_recipients": True,
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/billing"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/monitoring"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		account, err := organizations.GetBillingAccount(ctx, &organizations.GetBillingAccountArgs{
			BillingAccount: pulumi.StringRef("000000-0000000-0000000-000000"),
		}, nil)
		if err != nil {
			return err
		}
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		notificationChannel, err := monitoring.NewNotificationChannel(ctx, "notification_channel", &monitoring.NotificationChannelArgs{
			DisplayName: pulumi.String("Example Notification Channel"),
			Type:        pulumi.String("email"),
			Labels: pulumi.StringMap{
				"email_address": pulumi.String("address@example.com"),
			},
		})
		if err != nil {
			return err
		}
		_, err = billing.NewBudget(ctx, "budget", &billing.BudgetArgs{
			BillingAccount: pulumi.String(account.Id),
			DisplayName:    pulumi.String("Example Billing Budget"),
			BudgetFilter: &billing.BudgetBudgetFilterArgs{
				Projects: pulumi.StringArray{
					pulumi.Sprintf("projects/%v", project.Number),
				},
			},
			Amount: &billing.BudgetAmountArgs{
				SpecifiedAmount: &billing.BudgetAmountSpecifiedAmountArgs{
					CurrencyCode: pulumi.String("USD"),
					Units:        pulumi.String("100000"),
				},
			},
			ThresholdRules: billing.BudgetThresholdRuleArray{
				&billing.BudgetThresholdRuleArgs{
					ThresholdPercent: pulumi.Float64(1),
				},
				&billing.BudgetThresholdRuleArgs{
					ThresholdPercent: pulumi.Float64(1),
					SpendBasis:       pulumi.String("FORECASTED_SPEND"),
				},
			},
			AllUpdatesRule: &billing.BudgetAllUpdatesRuleArgs{
				MonitoringNotificationChannels: pulumi.StringArray{
					notificationChannel.ID(),
				},
				DisableDefaultIamRecipients: pulumi.Bool(true),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var account = Gcp.Organizations.GetBillingAccount.Invoke(new()
    {
        BillingAccount = "000000-0000000-0000000-000000",
    });

    var project = Gcp.Organizations.GetProject.Invoke();

    var notificationChannel = new Gcp.Monitoring.NotificationChannel("notification_channel", new()
    {
        DisplayName = "Example Notification Channel",
        Type = "email",
        Labels = 
        {
            { "email_address", "address@example.com" },
        },
    });

    var budget = new Gcp.Billing.Budget("budget", new()
    {
        BillingAccount = account.Apply(getBillingAccountResult => getBillingAccountResult.Id),
        DisplayName = "Example Billing Budget",
        BudgetFilter = new Gcp.Billing.Inputs.BudgetBudgetFilterArgs
        {
            Projects = new[]
            {
                $"projects/{project.Apply(getProjectResult => getProjectResult.Number)}",
            },
        },
        Amount = new Gcp.Billing.Inputs.BudgetAmountArgs
        {
            SpecifiedAmount = new Gcp.Billing.Inputs.BudgetAmountSpecifiedAmountArgs
            {
                CurrencyCode = "USD",
                Units = "100000",
            },
        },
        ThresholdRules = new[]
        {
            new Gcp.Billing.Inputs.BudgetThresholdRuleArgs
            {
                ThresholdPercent = 1,
            },
            new Gcp.Billing.Inputs.BudgetThresholdRuleArgs
            {
                ThresholdPercent = 1,
                SpendBasis = "FORECASTED_SPEND",
            },
        },
        AllUpdatesRule = new Gcp.Billing.Inputs.BudgetAllUpdatesRuleArgs
        {
            MonitoringNotificationChannels = new[]
            {
                notificationChannel.Id,
            },
            DisableDefaultIamRecipients = true,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetBillingAccountArgs;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.monitoring.NotificationChannel;
import com.pulumi.gcp.monitoring.NotificationChannelArgs;
import com.pulumi.gcp.billing.Budget;
import com.pulumi.gcp.billing.BudgetArgs;
import com.pulumi.gcp.billing.inputs.BudgetBudgetFilterArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountSpecifiedAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetThresholdRuleArgs;
import com.pulumi.gcp.billing.inputs.BudgetAllUpdatesRuleArgs;
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) {
        final var account = OrganizationsFunctions.getBillingAccount(GetBillingAccountArgs.builder()
            .billingAccount("000000-0000000-0000000-000000")
            .build());

        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var notificationChannel = new NotificationChannel("notificationChannel", NotificationChannelArgs.builder()
            .displayName("Example Notification Channel")
            .type("email")
            .labels(Map.of("email_address", "address@example.com"))
            .build());

        var budget = new Budget("budget", BudgetArgs.builder()
            .billingAccount(account.id())
            .displayName("Example Billing Budget")
            .budgetFilter(BudgetBudgetFilterArgs.builder()
                .projects(String.format("projects/%s", project.number()))
                .build())
            .amount(BudgetAmountArgs.builder()
                .specifiedAmount(BudgetAmountSpecifiedAmountArgs.builder()
                    .currencyCode("USD")
                    .units("100000")
                    .build())
                .build())
            .thresholdRules(            
                BudgetThresholdRuleArgs.builder()
                    .thresholdPercent(1.0)
                    .build(),
                BudgetThresholdRuleArgs.builder()
                    .thresholdPercent(1.0)
                    .spendBasis("FORECASTED_SPEND")
                    .build())
            .allUpdatesRule(BudgetAllUpdatesRuleArgs.builder()
                .monitoringNotificationChannels(notificationChannel.id())
                .disableDefaultIamRecipients(true)
                .build())
            .build());

    }
}
resources:
  budget:
    type: gcp:billing:Budget
    properties:
      billingAccount: ${account.id}
      displayName: Example Billing Budget
      budgetFilter:
        projects:
          - projects/${project.number}
      amount:
        specifiedAmount:
          currencyCode: USD
          units: '100000'
      thresholdRules:
        - thresholdPercent: 1
        - thresholdPercent: 1
          spendBasis: FORECASTED_SPEND
      allUpdatesRule:
        monitoringNotificationChannels:
          - ${notificationChannel.id}
        disableDefaultIamRecipients: true
  notificationChannel:
    type: gcp:monitoring:NotificationChannel
    name: notification_channel
    properties:
      displayName: Example Notification Channel
      type: email
      labels:
        email_address: address@example.com
variables:
  account:
    fn::invoke:
      function: gcp:organizations:getBillingAccount
      arguments:
        billingAccount: 000000-0000000-0000000-000000
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The allUpdatesRule property defines where alerts are sent. The monitoringNotificationChannels array lists notification channel IDs (email, Slack, PagerDuty, etc.). Setting disableDefaultIamRecipients to true prevents automatic notifications to billing account IAM members, giving you full control over who receives alerts.

Define budgets for custom date ranges

Projects with fixed timelines or fiscal years that don’t align with calendar months need custom budget periods.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const account = gcp.organizations.getBillingAccount({
    billingAccount: "000000-0000000-0000000-000000",
});
const project = gcp.organizations.getProject({});
const budget = new gcp.billing.Budget("budget", {
    billingAccount: account.then(account => account.id),
    displayName: "Example Billing Budget",
    budgetFilter: {
        projects: [project.then(project => `projects/${project.number}`)],
        creditTypesTreatment: "EXCLUDE_ALL_CREDITS",
        services: ["services/24E6-581D-38E5"],
        customPeriod: {
            startDate: {
                year: 2022,
                month: 1,
                day: 1,
            },
            endDate: {
                year: 2023,
                month: 12,
                day: 31,
            },
        },
    },
    amount: {
        specifiedAmount: {
            currencyCode: "USD",
            units: "100000",
        },
    },
    thresholdRules: [
        {
            thresholdPercent: 0.5,
        },
        {
            thresholdPercent: 0.9,
        },
    ],
});
import pulumi
import pulumi_gcp as gcp

account = gcp.organizations.get_billing_account(billing_account="000000-0000000-0000000-000000")
project = gcp.organizations.get_project()
budget = gcp.billing.Budget("budget",
    billing_account=account.id,
    display_name="Example Billing Budget",
    budget_filter={
        "projects": [f"projects/{project.number}"],
        "credit_types_treatment": "EXCLUDE_ALL_CREDITS",
        "services": ["services/24E6-581D-38E5"],
        "custom_period": {
            "start_date": {
                "year": 2022,
                "month": 1,
                "day": 1,
            },
            "end_date": {
                "year": 2023,
                "month": 12,
                "day": 31,
            },
        },
    },
    amount={
        "specified_amount": {
            "currency_code": "USD",
            "units": "100000",
        },
    },
    threshold_rules=[
        {
            "threshold_percent": 0.5,
        },
        {
            "threshold_percent": 0.9,
        },
    ])
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/billing"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		account, err := organizations.GetBillingAccount(ctx, &organizations.GetBillingAccountArgs{
			BillingAccount: pulumi.StringRef("000000-0000000-0000000-000000"),
		}, nil)
		if err != nil {
			return err
		}
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		_, err = billing.NewBudget(ctx, "budget", &billing.BudgetArgs{
			BillingAccount: pulumi.String(account.Id),
			DisplayName:    pulumi.String("Example Billing Budget"),
			BudgetFilter: &billing.BudgetBudgetFilterArgs{
				Projects: pulumi.StringArray{
					pulumi.Sprintf("projects/%v", project.Number),
				},
				CreditTypesTreatment: pulumi.String("EXCLUDE_ALL_CREDITS"),
				Services: pulumi.StringArray{
					pulumi.String("services/24E6-581D-38E5"),
				},
				CustomPeriod: &billing.BudgetBudgetFilterCustomPeriodArgs{
					StartDate: &billing.BudgetBudgetFilterCustomPeriodStartDateArgs{
						Year:  pulumi.Int(2022),
						Month: pulumi.Int(1),
						Day:   pulumi.Int(1),
					},
					EndDate: &billing.BudgetBudgetFilterCustomPeriodEndDateArgs{
						Year:  pulumi.Int(2023),
						Month: pulumi.Int(12),
						Day:   pulumi.Int(31),
					},
				},
			},
			Amount: &billing.BudgetAmountArgs{
				SpecifiedAmount: &billing.BudgetAmountSpecifiedAmountArgs{
					CurrencyCode: pulumi.String("USD"),
					Units:        pulumi.String("100000"),
				},
			},
			ThresholdRules: billing.BudgetThresholdRuleArray{
				&billing.BudgetThresholdRuleArgs{
					ThresholdPercent: pulumi.Float64(0.5),
				},
				&billing.BudgetThresholdRuleArgs{
					ThresholdPercent: pulumi.Float64(0.9),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var account = Gcp.Organizations.GetBillingAccount.Invoke(new()
    {
        BillingAccount = "000000-0000000-0000000-000000",
    });

    var project = Gcp.Organizations.GetProject.Invoke();

    var budget = new Gcp.Billing.Budget("budget", new()
    {
        BillingAccount = account.Apply(getBillingAccountResult => getBillingAccountResult.Id),
        DisplayName = "Example Billing Budget",
        BudgetFilter = new Gcp.Billing.Inputs.BudgetBudgetFilterArgs
        {
            Projects = new[]
            {
                $"projects/{project.Apply(getProjectResult => getProjectResult.Number)}",
            },
            CreditTypesTreatment = "EXCLUDE_ALL_CREDITS",
            Services = new[]
            {
                "services/24E6-581D-38E5",
            },
            CustomPeriod = new Gcp.Billing.Inputs.BudgetBudgetFilterCustomPeriodArgs
            {
                StartDate = new Gcp.Billing.Inputs.BudgetBudgetFilterCustomPeriodStartDateArgs
                {
                    Year = 2022,
                    Month = 1,
                    Day = 1,
                },
                EndDate = new Gcp.Billing.Inputs.BudgetBudgetFilterCustomPeriodEndDateArgs
                {
                    Year = 2023,
                    Month = 12,
                    Day = 31,
                },
            },
        },
        Amount = new Gcp.Billing.Inputs.BudgetAmountArgs
        {
            SpecifiedAmount = new Gcp.Billing.Inputs.BudgetAmountSpecifiedAmountArgs
            {
                CurrencyCode = "USD",
                Units = "100000",
            },
        },
        ThresholdRules = new[]
        {
            new Gcp.Billing.Inputs.BudgetThresholdRuleArgs
            {
                ThresholdPercent = 0.5,
            },
            new Gcp.Billing.Inputs.BudgetThresholdRuleArgs
            {
                ThresholdPercent = 0.9,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetBillingAccountArgs;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.billing.Budget;
import com.pulumi.gcp.billing.BudgetArgs;
import com.pulumi.gcp.billing.inputs.BudgetBudgetFilterArgs;
import com.pulumi.gcp.billing.inputs.BudgetBudgetFilterCustomPeriodArgs;
import com.pulumi.gcp.billing.inputs.BudgetBudgetFilterCustomPeriodStartDateArgs;
import com.pulumi.gcp.billing.inputs.BudgetBudgetFilterCustomPeriodEndDateArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetAmountSpecifiedAmountArgs;
import com.pulumi.gcp.billing.inputs.BudgetThresholdRuleArgs;
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) {
        final var account = OrganizationsFunctions.getBillingAccount(GetBillingAccountArgs.builder()
            .billingAccount("000000-0000000-0000000-000000")
            .build());

        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var budget = new Budget("budget", BudgetArgs.builder()
            .billingAccount(account.id())
            .displayName("Example Billing Budget")
            .budgetFilter(BudgetBudgetFilterArgs.builder()
                .projects(String.format("projects/%s", project.number()))
                .creditTypesTreatment("EXCLUDE_ALL_CREDITS")
                .services("services/24E6-581D-38E5")
                .customPeriod(BudgetBudgetFilterCustomPeriodArgs.builder()
                    .startDate(BudgetBudgetFilterCustomPeriodStartDateArgs.builder()
                        .year(2022)
                        .month(1)
                        .day(1)
                        .build())
                    .endDate(BudgetBudgetFilterCustomPeriodEndDateArgs.builder()
                        .year(2023)
                        .month(12)
                        .day(31)
                        .build())
                    .build())
                .build())
            .amount(BudgetAmountArgs.builder()
                .specifiedAmount(BudgetAmountSpecifiedAmountArgs.builder()
                    .currencyCode("USD")
                    .units("100000")
                    .build())
                .build())
            .thresholdRules(            
                BudgetThresholdRuleArgs.builder()
                    .thresholdPercent(0.5)
                    .build(),
                BudgetThresholdRuleArgs.builder()
                    .thresholdPercent(0.9)
                    .build())
            .build());

    }
}
resources:
  budget:
    type: gcp:billing:Budget
    properties:
      billingAccount: ${account.id}
      displayName: Example Billing Budget
      budgetFilter:
        projects:
          - projects/${project.number}
        creditTypesTreatment: EXCLUDE_ALL_CREDITS
        services:
          - services/24E6-581D-38E5
        customPeriod:
          startDate:
            year: 2022
            month: 1
            day: 1
          endDate:
            year: 2023
            month: 12
            day: 31
      amount:
        specifiedAmount:
          currencyCode: USD
          units: '100000'
      thresholdRules:
        - thresholdPercent: 0.5
        - thresholdPercent: 0.9
variables:
  account:
    fn::invoke:
      function: gcp:organizations:getBillingAccount
      arguments:
        billingAccount: 000000-0000000-0000000-000000
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The customPeriod property inside budgetFilter defines a specific date range for the budget. The startDate and endDate properties set the beginning and end of the tracking period. This is useful for project-based budgets or fiscal years that don’t match calendar boundaries. The creditTypesTreatment property set to EXCLUDE_ALL_CREDITS ensures only actual spending (not credits) counts toward the budget.

Beyond these examples

These snippets focus on specific budget-level features: fixed and relative budget amounts, spending filters, and notification routing and custom periods. They’re intentionally minimal rather than full cost management solutions.

The examples may reference pre-existing infrastructure such as billing accounts with known IDs, projects with known numbers, and monitoring notification channels for alert routing. They focus on configuring the budget rather than provisioning the surrounding billing infrastructure.

To keep things focused, common budget patterns are omitted, including:

  • Forecasted spend thresholds (spendBasis property)
  • Project-level recipient notifications (enableProjectLevelRecipients)
  • Calendar period configuration (alternative to customPeriod)
  • Ownership scope controls (ownershipScope property)

These omissions are intentional: the goal is to illustrate how each budget feature is wired, not provide drop-in cost management modules. See the Billing Budget resource reference for all available configuration options.

Let's configure GCP Billing Budgets

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Authentication & Permissions
Why am I getting a 403 error when creating a budget?
If you’re using User Application Default Credentials, you must set billing_project and user_project_override = true in your provider configuration. Your account also needs the serviceusage.services.use permission on the billing project.
Budget Configuration
Can I change the billing account after creating a budget?
No, billingAccount is immutable. Changing it forces recreation of the budget resource.
What's the difference between specifiedAmount and lastPeriodAmount?
specifiedAmount sets a fixed budget amount in a specific currency, while lastPeriodAmount automatically uses the previous period’s spend as your budget. These options are mutually exclusive.
What's the character limit for budget display names?
Budget display names must be 60 characters or fewer.
Alerts & Notifications
How do budget threshold alerts work?
Configure thresholdRules with threshold percentages (e.g., 0.5 for 50%). You can set spendBasis to CURRENT_SPEND (default) for actual spend or FORECASTED_SPEND to alert on projected spend.
What's the difference between thresholdRules and allUpdatesRule?
thresholdRules trigger alerts only when specific spending thresholds are crossed. allUpdatesRule sends notifications on every spend update, regardless of thresholds.
How do I send budget alerts to monitoring channels?
Configure allUpdatesRule.monitoringNotificationChannels with notification channel IDs. You can also set disableDefaultIamRecipients to control whether IAM-based recipients receive alerts.
How do I notify project-level billing admins?
Set allUpdatesRule.enableProjectLevelRecipients = true to automatically notify project billing administrators.
Filtering & Scope
How do I filter budgets to specific projects or services?
Use budgetFilter to scope your budget. Set projects with project numbers (format: projects/{number}), services with service IDs, or resourceAncestors with organization/folder IDs.
How do I control whether credits count toward my budget?
Set budgetFilter.creditTypesTreatment to control credit handling. Use INCLUDE_SPECIFIED_CREDITS with a creditTypes list, or EXCLUDE_ALL_CREDITS to ignore all credits.
Can I set a custom budget period instead of calendar months?
Yes, use budgetFilter.customPeriod with startDate and endDate objects specifying year, month, and day.

Using a different cloud?

Explore monitoring guides for other cloud providers: