CLI tool
mivano/azure-cost-cli avatar
mivano/azure-cost-cli

azure-cost-cli: pulling Azure subscription cost into a shell pipeline

CLI tool to perform cost analysis on your Azure subscription

1,120 stars151 forksC#Apache-2.0

At a glance

What is it?
azure-cost-cli is a .NET global tool that queries the Azure Cost Management API and prints subscription cost as console text, JSON, markdown or CSV, with commands for daily cost, per-resource cost, tag cost, budgets, diffs and anomaly detection. It is built for pipelines, and it inherits the Cost Management API's own coverage limits.
Who is it for?
Adopt azure-cost-cli if you want Azure cost data in a script, a CI job or a scheduled report, in a machine-readable format you can pipe, and you can work within the Cost Management API's coverage. Do not adopt it as a general Azure governance platform, since it is a read-only cost query tool, and check your subscription type first because the API is not available on every one.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A cost query tool, not a cost management platform

azure-cost-cli is described as a simple command line tool to get the cost of your Azure subscription. It uses the Azure Cost Management API to get the cost and output the results to the console, text, csv, markdown or JSON, and the README's stated reason for that design is so it can be used in a workflow to get the cost of your subscription and use it in subsequent steps.

That framing sets the scope precisely. This is a read-side tool. It asks the Cost Management API what things cost and prints the answer in a format a script can consume. It is not a tagging policy enforcer, it does not set budgets, it does not alert anyone, and it does not reconcile invoices.

The topic tags make the intent clear too: azure, cli, command-line, cost, cost-management, dotnet-tool, finops and governance. The dotnet-tool tag is the important one, because it tells you the distribution mechanism, and the tool is installed with the standard.NET tool mechanism rather than as a standalone binary.

The primary language is C#, the licence is Apache-2.0, and the release history shows an active line: 0.60.0 on 2026-09-28, 0.59.0 and 0.58.0 both on 2026-08-16. The repository is not archived and the last push was on 2026-10-19, so the tool is being worked on rather than merely maintained.

The audience is a FinOps engineer, a platform team, or a developer with a scheduled report who needs the number in a file rather than in a portal. The people it does not serve are those who want a dashboard, and those whose problem is that the bill is too high rather than that the bill is hard to query.

The command set, and the diff command that makes it a pipeline tool

The help output in the README is the best catalogue of what the tool does, and it is worth reading as a list of questions rather than a list of subcommands.

accumulatedCost shows the accumulated cost details, which is the headline number. costByResource shows cost broken down per resource, and costByTag shows cost by one or more tag keys, which is how you get a cost centre or a team out of the data. dailyCosts shows the daily cost grouped by a dimension, and the README's screenshots show it grouped by MeterCategory and by ResourceGroup, with a light and a dark variant. budgets gets the available budgets, and regions gets the available Azure regions.

Then there are the two that make it more than a report generator. The diff command shows the cost difference between two timeframes, and it takes two forms. You can compare two result files, for example `azure-cost diff --compare-to new.json --compare-from old.json`, or you can compare two date ranges, for example `azure-cost diff --source-from 2025-03-01 --source-to 2025-03-31 --from 2025-04-01 --to 2025-04-30`. That second form is the interesting one for a workflow: you can snapshot this month's cost and last month's cost and produce a month-on-month change without writing the comparison yourself.

detectAnomalies detects anomalies and trends, and the README says this can be used to further automate reporting. The example is `azure-cost detectAnomalies --dimension ResourceId --recent-activity-days 4`, so it works on a dimension with a recency window rather than over the whole billing period.

There is also a what-if command, which runs what-if scenarios, and a costByTag example with a tag key.

The set is a coherent answer to the questions a cost owner actually asks: how much so far, where did it go, which tag owns it, how does this month compare, is anything unusual, what did we set as a budget, and what would this change cost. What is missing from that list, and missing from the whole tool, is anything that changes the bill.

Installing it as a .NET global tool

The prerequisites are short. You need a .NET 8.0 or .NET 10.0 runtime, and you need either an Azure CLI authenticated with `az login` or an Azure identity holding the Cost Management Reader role.

Installation is a single global tool install:

bash
dotnet tool install --global azure-cost-cli

Upgrading works the same way, since the tool is on NuGet:

bash
dotnet tool update --global azure-cost-cli

The README notes two details about the update path. With a `--version` parameter you can specify a specific version to install, and the `--no-cache` parameter forces a re-download of the package if it cannot find the latest version. That second one is worth remembering, because a stale local NuGet cache is a common reason a tool update appears to do nothing.

The invocation is `azure-cost`, and the help is the discovery mechanism. `azure-cost --help` prints the full option list, and some of the commands have additional parameters that are shown by adding the specific command with the `--help` option.

The repository layout is small and tells you where the code lives: src/ for the project, tests/ for the test suite, an issues/ directory, a .devcontainer/ for a containerised development environment, .vscode/ for editor configuration, and a Directory.Build.props at the root for the shared build properties. There is an AGENTS.md, a CODEOWNERS file, and a .github/ directory for the workflows. The NuGet badge in the README points at the azure-cost-cli package, and the release badge points at the GitHub releases page.

The .devcontainer/ directory is a small but real signal about the project. A devcontainer means a contributor can open the repository in a container with the right SDK and tools already present, which matters for a .NET project where the runtime version, the SDK and the Azure CLI all have to line up.

The output and scoping options, and the JMESPath escape hatch

The global options are where most of the practical value sits, and the README lists them in full.

Output format is set with -o, --output, and the valid values are Console, Json, JsonC, Markdown, Text and Csv, defaulting to Console. The presence of both Json and JsonC is a hint that the tool distinguishes a plain JSON array from a more structured JSON output. The --skipHeader option skips header creation for specific output formats, and the README explains the reason: it is useful when appending the output from multiple runs into one file. That is a small flag that reveals the intended workflow, several scoped queries concatenated into a single report.

Scoping is done with -s for the subscription id, -g for the resource group, -b for the billing account and -e for the enrollment account. The README notes that starting from version 0.35 you can select a scope besides only the subscription, and that the resource group needs to be used in combination with the subscription id. When no subscription id is given, the tool fetches the actively selected one of the Azure CLI.

Two options make this a query language rather than a report generator. The --query option takes a JMESPath query string, with a pointer to jmespath.org for information and examples, so you can reshape the result set yourself instead of writing a parser. The --filter option filters the output by specified properties, can be multiple values, and defaults to no filtering. Together they mean the tool does not have to grow a new flag for every report shape you need.

Two more are worth noting. The -m, --metric option chooses between ActualCost and AmortizedCost, defaulting to ActualCost, which is the difference between what you were billed in the period and what you consumed. And --useUSD forces the use of USD for the currency, defaulting to false to use the currency returned by the API, which matters for a multi-currency estate where you need a common unit.

The two base address options are the escape hatch for sovereign clouds. --costApiBaseAddress defaults to https://management.azure.com/ and --priceApiBaseAddress defaults to https://prices.azure.com/, and both can be set to a different value to use a different cloud, with the government examples given as https://management.usgovcloudapi.net/ and https://prices.azure.us/.

The subscription compatibility caveat that comes first in the README

The most important paragraph in the README is the warning, and it appears before the installation instructions. The tool uses the Azure Cost Management API, and not all Azure subscription types are supported by this API, with sponsored subscriptions given as an example. The README says to check if your subscription is compatible before using the tool.

It then tells you how to check. You can use the `az account subscription show --subscription-id yourid --query '[subscriptionPolicies.quotaId]' -o tsv` command to fetch the subscription's quota id, and validate the resulting value against the list linked in the README.

This is a real constraint rather than a technicality. A sponsored subscription, for instance, does not expose cost data through the Cost Management API, so the tool will not be able to query it. That makes the check a precondition, not a troubleshooting step, and it is worth running before you build anything on top of the tool.

There is a second caveat in the same area, and it is about data freshness rather than availability. The Cost Management API is a reporting API, not a billing system, so the cost it returns for the current month is the accumulated cost reported so far, not a final figure. The default timeframe is BillingMonthToDate, and the --from and --to options default to the first day of the previous month and the current date respectively. A pipeline that alerts on a threshold needs to tolerate that, because the number it reads mid-month is a moving target and the final number arrives later.

One more option is worth calling out because it is easy to miss. The --others-cutoff option sets the number of items to show before collapsing the rest into an Others item, and it defaults to 10. That is the difference between a cost-by-resource report with 400 rows and one with 10 rows plus an Others line, which is what you want in a console and not what you want in a JSON file you are going to parse.

What this tool does not do, and the alternative approaches

There are three limits, and the second one is the one that decides whether you need this at all.

The first is the API coverage already described, plus the fact that the tool is read-only. It reports cost; it does not create budgets, it does not apply tags, it does not fire alerts and it does not shut anything down. If your problem is that nobody is watching the bill, this tool is the wrong shape, because watching is a scheduled job plus a threshold plus a notification, and this is only the first of those.

The second limit is that it is a cost query, not a cost allocation engine. You can group by tag and by resource group, and the --includeTags option brings tags into the output for the DailyCost report with Json, JsonC or Csv output, and it is ignored in the other reports and formats. But there is no concept of shared cost, no allocation of a subscription-level charge across the teams that caused it, and no treatment of the difference between a resource that exists and a resource that is idle. A tool built for showback and chargeback has to do that arithmetic, and this one does not attempt it.

The third is the currency and granularity story. ActualCost and AmortizedCost are both available and the output can be forced to USD, but the granularity of what is reported is the Cost Management API's, which is metered, daily and dimension-based, not per-operation.

The alternatives differ in approach along two axes. The first axis is the portal. Azure's own Cost Management blades and the Cost Management API used directly give you the same data with a full console and alerting, at the cost of a much larger API surface and no command line pipeline. Using the API directly from your own script is the other end: the same data, no tool, and you write the query, the formatting and the output format yourself, which is what this package saves you from when you do not want to write JMESPath by hand.

The second axis is the cost management platform. A commercial FinOps product adds allocation, showback, chargeback, dashboards, budget alerts and recommendation engines on top of the same underlying data, and it is a much larger commitment than a single .NET tool. Between the raw API and a full platform, this tool sits at the useful middle: it handles the authentication, the query construction and the output formatting for the cost queries, and it does not try to be a governance product.

The deciding question is therefore whether you need a number in a script or a policy engine. A number in a script, this is a good fit. A policy engine, you need something else, and this tool will not grow into it.

Editorial conclusion

Adopt azure-cost-cli if you want Azure cost data in a script, a CI job or a scheduled report, in a machine-readable format you can pipe, and you can work within the Cost Management API's coverage. Do not adopt it as a general Azure governance platform, since it is a read-only cost query tool, and check your subscription type first because the API is not available on every one. Verify first that the subscription's quota id permits Cost Management access, that your identity holds Cost Management Reader or that you are logged in with the Azure CLI, and that the cost metric you pick, ActualCost or AmortizedCost, is the one your organisation reports against.

Frequently asked questions

How do I install azure-cost-cli?

It is distributed as a .NET global tool, so you install it with `dotnet tool install --global azure-cost-cli`. You need a .NET 8.0 or .NET 10.0 runtime, and either an Azure CLI authenticated with az login or an identity holding the Cost Management Reader role.

Does azure-cost-cli work with every Azure subscription?

No. The tool uses the Azure Cost Management API and the README warns that not all subscription types are supported, naming sponsored subscriptions as an example. You can check by running `az account subscription show --subscription-id yourid --query '[subscriptionPolicies.quotaId]' -o tsv` and validating the quota id.

What output formats does the azure-cost command support?

The -o, --output option takes Console, Json, JsonC, Markdown, Text and Csv, defaulting to Console. The --skipHeader option suppresses headers for specific formats, which the README notes is useful when appending output from multiple runs into one file.

Can azure-cost-cli compare two periods of Azure spending?

Yes. The diff command shows the cost difference between two timeframes, either by comparing two saved result files with --compare-to and --compare-from, or by comparing two date ranges using --source-from, --source-to, --from and --to.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. mivano/azure-cost-cli on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mivano-azure-cost-cli.svg)](https://hysenlabs.com/projects/mivano-azure-cost-cli)

Was this useful?