Configure GCP Billing Budgets

The gcp:billing/budget:Budget resource, part of the Pulumi GCP provider, defines billing budgets that track spending against fixed amounts or previous periods, with threshold-based alerts. This guide focuses on four capabilities: fixed and last-period budget amounts, project and service filtering, notification channel integration, and custom date ranges.

Budgets require a billing account ID and may reference project numbers, service IDs, or monitoring notification channels that must exist separately. 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

The amount property defines your spending limit using specifiedAmount with a currency code and units. The thresholdRules array sets percentage thresholds that trigger alerts; here, you’re notified when spending reaches 50% of the $100,000 budget. Without budgetFilter, the budget tracks all spending in the billing account.

Track spending against previous period costs

Teams with predictable monthly spending often budget based on the previous period’s actual costs 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 (
	"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 automatically adjust to match the previous period’s spending. The budgetFilter scopes the budget to specific projects using their project numbers. This configuration alerts when current spending exceeds 10% of what you spent last period.

Filter budgets 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 (
	"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 narrows the budget’s scope. The projects array limits tracking to specific project numbers, services filters to particular GCP services (like Compute Engine), and creditTypes specifies which credit types to include. The creditTypesTreatment property controls whether credits reduce your tracked spending. The resourceAncestors property can scope budgets to entire organizations or folders. This example tracks two threshold rules: one at 50% of actual spend, another at 90% of forecasted spend.

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 (
	"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 go. The monitoringNotificationChannels array lists notification channel IDs that receive alerts on every budget update. Setting disableDefaultIamRecipients to true prevents automatic notifications to billing account IAM members, giving you precise 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 (
	"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 budget’s active period using year, month, and day values. This configuration tracks spending from January 1, 2022 through December 31, 2023, useful for project-based budgets or non-calendar fiscal years.

Beyond these examples

These snippets focus on specific budget-level features: fixed and last-period budget amounts, project, service, and credit filtering, and notification channel integration. They’re intentionally minimal rather than full cost management solutions.

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

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

  • Project-level recipient notifications (enableProjectLevelRecipients)
  • Ownership scope controls (ownershipScope)
  • Calendar period configuration (calendarPeriod)
  • Forecasted spend thresholds (spendBasis variations)

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?
When using User Application Default Credentials, you must set billingProject and userProjectOverride: true in your provider configuration. Your account also needs the serviceusage.services.use permission on the specified billing project.
Budget Amount & Configuration
What's the difference between specifiedAmount and lastPeriodAmount?
Use specifiedAmount to set a fixed budget with currencyCode and units. Use lastPeriodAmount: true to automatically base the budget on the previous period’s spend.
Can I change the billing account after creating a budget?
No, billingAccount is immutable. You must recreate the budget to use a different billing account.
What's the character limit for budget display names?
Display names must be 60 characters or less.
Filtering & Scope
How do I filter budgets by specific projects or services?
Configure budgetFilter with a projects array (format: projects/{number}) and services array. You can also add resourceAncestors to filter by organization or folder.
How do I include or exclude credits from my budget?
Set budgetFilter.creditTypesTreatment to INCLUDE_SPECIFIED_CREDITS or EXCLUDE_ALL_CREDITS, then specify which credit types (like PROMOTION or FREE_TIER) in the creditTypes array.
How do I create a budget for a custom time period?
Configure budgetFilter.customPeriod with startDate and endDate objects, each containing year, month, and day fields.
Notifications & Alerts
How do I set up budget alerts at multiple spending thresholds?
Add multiple entries to the thresholdRules array with different thresholdPercent values. You can also set spendBasis: FORECASTED_SPEND for forecast-based alerts instead of actual spend.
How do I send budget notifications to a monitoring channel?
Set allUpdatesRule.monitoringNotificationChannels to an array of notification channel IDs. You can set disableDefaultIamRecipients: true to disable default IAM-based recipients.
How do I notify project-level recipients instead of using monitoring channels?
Set allUpdatesRule.enableProjectLevelRecipients: true with an empty monitoringNotificationChannels array to send notifications to project-level billing recipients.

Using a different cloud?

Explore monitoring guides for other cloud providers: