Skip to content

About

AWS Cost Explorer

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

AWS Cost CLI

This is a simple command line tool to get the cost of your AWS account. It uses the AWS Cost Explorer API to get the cost and output the results to the console, text, csv, markdown or JSON. E.g. so it can be used in a workflow to get the cost of your account and use it in subsequent steps.

It is modeled on the excellent azure-cost-cli and follows the same commands, options and output formats where AWS has an equivalent.

⚠️ Important: AWS charges for every Cost Explorer API request (USD 0.01 per request at the time of writing). A single accumulatedCost run makes 4–5 requests. See Is there cost involved?

        AWS Cost Overview for my-account (123456789012) from 10/1/2026 to 10/22/2026
╭─          AWS Costs           ─╮           Accumulated cost in USD
│    Today:       4.10 USD       │  01 Oct  ██ 3.95
│  Yesterday:     4.32 USD       │  02 Oct  ███ 8.02
│ Since start     92.47 USD      │  ...
│    of Oct:                     │  22 Oct  ████████████████████ 92.47
│ Forecast for   131.20 USD      │  23 Oct  ████████████████████ 96.41
│     Oct:                       │  ...
│ Last 7 days:    29.83 USD      │  31 Oct  ████████████████████████████ 131.2
│ Last 30 days:   92.47 USD      │
│   Total in      92.47 USD      │
│  timeframe:                    │
╰────────────────────────────────╯
╭─          By Service          ─╮
│ ■ Amazon Elastic Compute Cloud - Compute 41.20 USD
│ ■ Amazon Relational Database Service 22.75 USD
│ ■ EC2 - Other 11.04 USD
│ ■ Amazon Simple Storage Service 6.31 USD
│ ...
╰────────────────────────────────╯
╭─          By Region           ─╮
│ ■ eu-west-1 80.12 USD
│ ■ us-east-1 11.90 USD
│ ■ global 0.45 USD
╰────────────────────────────────╯

Installation

Prerequisites

The tool is not published to nuget.org (yet), so you install it from a package you build locally. Pick one of the options below.

Option 1: Global .NET tool for the current user (recommended)

A .NET global tool is installed per user into ~/.dotnet/tools (%USERPROFILE%\.dotnet\tools on Windows) and is available from any directory.

# 1. Build the NuGet package (written to src/nupkg)
dotnet pack src/aws-cost-cli.csproj -c Release

# 2. Install it globally for your user from that folder
dotnet tool install --global aws-cost-cli --add-source src/nupkg

# 3. Use it from anywhere
aws-cost --version
aws-cost accumulatedCost

~/.dotnet/tools is added to your PATH by the .NET SDK installer. If aws-cost is not found, open a new terminal, or add the folder yourself:

# Windows (PowerShell) - permanently for the current user
[Environment]::SetEnvironmentVariable("PATH", $env:PATH + ";$env:USERPROFILE\.dotnet\tools", "User")
# Linux / macOS - add to ~/.bashrc or ~/.zshrc
export PATH="$PATH:$HOME/.dotnet/tools"

Option 2: Share with a team via a NuGet feed

Copy the .nupkg from src/nupkg to a shared folder (or push it to a private feed such as Azure Artifacts, GitHub Packages or AWS CodeArtifact). Every user then installs it once:

# From a file share
dotnet tool install --global aws-cost-cli --add-source \\fileserver\nuget

# From a private feed that is already configured in your nuget.config
dotnet tool install --global aws-cost-cli

To install into a specific folder instead of the per-user location (for example a shared tools folder on a build agent), use --tool-path:

dotnet tool install aws-cost-cli --add-source src/nupkg --tool-path C:\tools\aws-cost

Option 3: Self-contained executable (no .NET required)

Publish a single executable that bundles the .NET runtime, then copy it to any machine:

# Windows x64 (use linux-x64, linux-arm64, osx-arm64, osx-x64 for other platforms)
dotnet publish src/aws-cost-cli.csproj -c Release -f net9.0 -r win-x64 --self-contained \
  -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true \
  -p:AssemblyName=aws-cost -o publish/win-x64

This produces publish/win-x64/aws-cost.exe (about 90 MB). Put it in a folder on your PATH, for example:

# Windows (PowerShell) - current user only, no admin rights required
New-Item -ItemType Directory -Force "$env:LOCALAPPDATA\Programs\aws-cost" | Out-Null
Copy-Item publish\win-x64\aws-cost.exe "$env:LOCALAPPDATA\Programs\aws-cost\"
[Environment]::SetEnvironmentVariable("PATH", $env:PATH + ";$env:LOCALAPPDATA\Programs\aws-cost", "User")
# Linux / macOS - current user
mkdir -p ~/.local/bin && cp publish/linux-x64/aws-cost ~/.local/bin/ && chmod +x ~/.local/bin/aws-cost

Run from source

dotnet run --project src -f net9.0 -- accumulatedCost

Upgrading

Bump the <Version> in src/aws-cost-cli.csproj, build a new package and update the installed tool:

dotnet pack src/aws-cost-cli.csproj -c Release
dotnet tool update --global aws-cost-cli --add-source src/nupkg

With a --version parameter, you can install a specific version. Use the --no-cache parameter to force a re-read of the package source if it cannot find the latest version.

Uninstalling

dotnet tool uninstall --global aws-cost-cli
dotnet tool list --global          # verify it is gone

For the self-contained executable, simply delete aws-cost.exe / aws-cost and remove the folder from your PATH.

Usage

You can invoke the tool using the aws-cost command. You can use the --help parameter to get a list of all available options.

aws-cost --help

Which will show:

USAGE:
    aws-cost [OPTIONS] [COMMAND]

EXAMPLES:
    aws-cost accumulatedCost
    aws-cost accumulatedCost --profile my-profile
    aws-cost accumulatedCost -o json
    aws-cost accumulatedCost -t TheLastMonth -o markdown
    aws-cost accumulatedCost --from 2026-01-01 --to 2026-03-31
    aws-cost accumulatedCost --filter REGION=eu-west-1 --filter tag:Environment=prod

OPTIONS:
                                DEFAULT
    -h, --help                                   Prints help information
    -v, --version                                Prints version information
        --debug                                  Increase logging verbosity to show all debug logs
        --no-color                               Disable ANSI color output. Useful for CI/logging environments
        --quiet                                  Suppress all status/progress messages. Only actual data output is written
    -p, --profile                                The AWS named profile to use. Defaults to the standard AWS credential chain
    -r, --region                                 The AWS region of the Cost Explorer endpoint. Defaults to us-east-1
    -o, --output                                 The output format to use. Defaults to Console (Console, Json, JsonC, Text, Markdown, Csv)
    -t, --timeframe                              The timeframe to use for the costs. Defaults to MonthToDate (MonthToDate, TheLastMonth, WeekToDate, Custom)
        --from                                   The start date (inclusive) to use for the costs
        --to                                     The end date (inclusive) to use for the costs
        --others-cutoff         10               The number of items to show before collapsing the rest into an 'Others' item
        --query                                  JMESPath query string, applicable for the Json output only
        --skipHeader                             Skip header creation for specific output formats
        --filter                                 Filter the costs. Format: DIMENSION=value1,value2 or tag:Key=value1,value2
    -m, --metric                UnblendedCost    The cost metric to use (UnblendedCost, BlendedCost, AmortizedCost, NetUnblendedCost, NetAmortizedCost)
        --endpoint-url <URL>                     Override the Cost Explorer endpoint URL
        --fail-if-over                           Fail with exit code 1 if total cost exceeds this amount

COMMANDS:
    accumulatedCost    Show the accumulated cost details

If the application is not working properly, you can use the --debug parameter to see the caller identity and every Cost Explorer request that is made.

Cost Explorer data is refreshed at least once every 24 hours, so "Today" is an estimate and can lag behind.

Authentication

The tool uses the standard AWS SDK for .NET credential chain, so anything that works for the AWS CLI works here:

Method How
Console login aws login (stores a login_session in ~/.aws/config)
IAM Identity Center (SSO) aws sso login --profile my-sso-profile, then aws-cost --profile my-sso-profile
Access keys aws configure, or the AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN env vars
Named profile --profile <name> or the AWS_PROFILE env var
Roles EC2 instance profiles, ECS task roles, EKS IRSA / Pod Identity, GitHub OIDC (AWS_WEB_IDENTITY_TOKEN_FILE)

The identity needs the following permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ce:GetCostAndUsage",
        "ce:GetCostForecast",
        "sts:GetCallerIdentity",
        "iam:ListAccountAliases"
      ],
      "Resource": "*"
    }
  ]
}

iam:ListAccountAliases is optional; it is only used to show a friendly account name. The AWS managed policy AWSBillingReadOnlyAccess also works.

In an AWS Organization, running against the management (payer) account shows the costs of all member accounts, including a By Linked Account breakdown. In a member account you only see that account's costs.

Global flags

These flags are available on every command:

Flag Description
--no-color Disable ANSI color and escape codes. Useful when piping output to files or running in CI environments where color codes appear as garbage.
--quiet Suppress all status spinners and progress messages. Only the actual data output is written. Useful for scripting or when redirecting output.
--debug Show verbose debug information including the caller identity and the Cost Explorer requests.
-v, --version Print the tool version.

Examples:

# Pipe clean output to a file without escape codes
aws-cost accumulatedCost -o text --no-color > report.txt

# Use in a script without spinner noise
aws-cost accumulatedCost -o json --quiet | jq '.totals.totalCostInTimeframe'

You can use this tool in a GitHub workflow to get the cost of your account and store the results in markdown as a Job Summary. Authenticate with GitHub OIDC so no long-lived keys are needed:

name: AWS Cost CLI Workflow

on:
  workflow_dispatch:
  schedule:
    - cron: '0 7 * * *'

permissions:
  id-token: write
  contents: read

jobs:
  run-aws-cost-cli:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '9.0.x'

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_COST_ROLE_ARN }}
          aws-region: us-east-1

      - name: Install AWS Cost CLI
        run: |
          dotnet pack src/aws-cost-cli.csproj -c Release
          dotnet tool install --global aws-cost-cli --add-source src/nupkg

      - name: Run AWS Cost CLI
        run: aws-cost accumulatedCost -o markdown --quiet >> $GITHUB_STEP_SUMMARY

CI/CD Cost Gates

Use the --fail-if-over <amount> flag to fail a pipeline step when costs exceed a threshold. When the total cost in the timeframe exceeds the specified amount, the command writes a warning to stderr and exits with code 1. Output is still written normally before the check, so piped output (e.g. to a file) is not affected.

Example: GitHub Actions cost gate

- name: Check AWS costs
  run: aws-cost accumulatedCost -o json --quiet --fail-if-over 500 > costs.json

If costs exceed 500, the step fails and the workflow stops (or you can use continue-on-error: true to proceed with a warning). The JSON output is still written to costs.json regardless.

Available commands

Accumulated Cost

This will retrieve the accumulated cost of the account. This is the total cost since the beginning of the period specified. It also fetches the forecast until the end of the month (when the timeframe includes today) and organises the costs by service, region and linked account. You can use the different formatters to get the results in different formats.

aws-cost accumulatedCost --profile prod

This is the default command when you do not specify a command.

Filter

With the --filter option you can pass in one or more Cost Explorer dimensions or tags to filter on.

aws-cost --filter "REGION=eu-west-1,eu-central-1" --filter "tag:owner=me"

In the example above, we look for costs in either eu-west-1 or eu-central-1 and having a tag named owner with the value me.

Commonly used dimensions: SERVICE, REGION, LINKED_ACCOUNT, USAGE_TYPE, INSTANCE_TYPE, RECORD_TYPE, PURCHASE_TYPE. Service names must match the Cost Explorer names exactly, e.g. SERVICE=Amazon Elastic Compute Cloud - Compute (quote values that contain spaces).

Filters are passed along to the Cost Explorer API, so less data is retrieved. Compared to the query, where the data is queried with a JMESPath expression and can be projected as well.

Multiple filters are combined with an and expression, while the values are split by the , and used as an or.

Tip: exclude credits and refunds from the totals with the -m NetUnblendedCost metric, or filter on RECORD_TYPE=Usage.

Query

Use the --query to specify a JMESPath expression. This allows you to filter the results. For example, to get the yesterday cost of the account, you can use the following query:

aws-cost -o json --query "totals.yesterdayCost"

Or to list only the services and their cost:

aws-cost -o json --query "byServiceNames[*].[ServiceName, Cost]"

will output:

[["Amazon Elastic Compute Cloud - Compute",41.2],["Amazon Relational Database Service",22.75],["EC2 - Other",11.04]]

For the JMESPath parsing, it uses the JMESPath.Net library. Not all constructions might be implemented yet.

Timeframe

The default timeframe is the month to date. You can specify a custom timeframe using the --from and --to parameters (setting both automatically switches to Custom). Dates use the ISO 8601 format (yyyy-MM-dd) and both are inclusive.

Options are:

  • MonthToDate
  • TheLastMonth
  • WeekToDate (starting on Sunday)
  • Custom

All dates are in UTC, which is what Cost Explorer uses. Cost Explorer keeps 13 months of history by default (up to 38 months when multi-year data is enabled).

Metric

Select the cost metric with -m / --metric:

Metric Description
UnblendedCost (default) Costs as they are charged, matching most of the bill
BlendedCost Average rates across an organization's consolidated billing family
AmortizedCost Upfront Reserved Instance / Savings Plans fees spread over the term
NetUnblendedCost Unblended cost after discounts (e.g. EDP, credits)
NetAmortizedCost Amortized cost after discounts

See Understanding your AWS Cost Datasets for details.

Output formats

The tool supports multiple output formats. The default is Console which will output the results to the console. You can specify a different format using the --output parameter. The following formats are supported:

Console

The default output format. It will output the results to the console in a graphical way, as shown at the top of this page.

Json / JsonC

The Json format is great for further processing of the data. It will output the results in a JSON format to the console. Using the > operator, you can redirect the output to a file. Use jsonc to get a colorized output.

aws-cost accumulatedCost -o json > cost.json
{
  "account": {
    "accountId": "123456789012",
    "alias": "my-account"
  },
  "timeframe": {
    "from": "2026-10-01",
    "to": "2026-10-22",
    "metric": "UnblendedCost"
  },
  "totals": {
    "todaysCost": 4.10,
    "yesterdayCost": 4.32,
    "sinceStartOfMonthCost": 92.47,
    "lastSevenDaysCost": 29.83,
    "lastThirtyDaysCost": 92.47,
    "totalCostInTimeframe": 92.47,
    "forecastedEndOfMonthCost": 131.20,
    "currency": "USD"
  },
  "cost": [
    { "Date": "2026-10-01", "Cost": 3.95, "Currency": "USD" },
    { "Date": "2026-10-02", "Cost": 4.07, "Currency": "USD" }
  ],
  "forecastedCosts": [
    { "Date": "2026-10-23", "Cost": 3.94, "Currency": "USD" }
  ],
  "byServiceNames": [
    { "ServiceName": "Amazon Elastic Compute Cloud - Compute", "Cost": 41.20, "Currency": "USD" }
  ],
  "byRegion": [
    { "Region": "eu-west-1", "Cost": 80.12, "Currency": "USD" }
  ],
  "byLinkedAccount": [
    { "LinkedAccount": "my-account (123456789012)", "Cost": 92.47, "Currency": "USD" }
  ]
}

Tip: Use the --query parameter here to manipulate the results, like filtering and projecting the data. Do keep in mind that it operates over the already fetched data.

Text

A simple textual format.

AWS Cost Overview for my-account (123456789012) from 10/1/2026 to 10/22/2026

Totals:
  Today: 4.10 USD
  Yesterday: 4.32 USD
  Since start of Oct: 92.47 USD
  Forecast for Oct: 131.20 USD
  Last 7 days: 29.83 USD
  Last 30 days: 92.47 USD
  Total cost in timeframe: 92.47 USD

By Service Name:
  Amazon Elastic Compute Cloud - Compute: 41.20 USD
  Amazon Relational Database Service: 22.75 USD
  EC2 - Other: 11.04 USD
  Amazon Simple Storage Service: 6.31 USD
  AmazonCloudWatch: 4.02 USD

By Region:
  eu-west-1: 80.12 USD
  us-east-1: 11.90 USD
  global: 0.45 USD

When the timeframe ends before today (e.g. -t TheLastMonth), the last day with data is used instead of "Today" and "Yesterday".

Csv

A CSV format with the daily costs, which can be used in Excel or other tools. It will use the default culture of your system for the separators. If you combine the output of multiple runs into one file (like using the >> to append to a file), you can use the --skipHeader parameter to prevent the header from being written multiple times.

aws-cost accumulatedCost -o csv > cost.csv
Date,Cost,Currency
10/1/2026,3.95000000,USD
10/2/2026,4.07000000,USD
10/3/2026,4.11000000,USD

Markdown

A markdown format. It will output the results in a series of simple tables, plus mermaid charts that render on GitHub.

aws-cost accumulatedCost -o markdown > cost.md
# AWS Cost Overview

> Accumulated UnblendedCost for account `my-account (123456789012)` from **10/1/2026** to **10/22/2026**

## Totals

|Period|Amount|
|---|---:|
|Today|4.10 USD|
|Yesterday|4.32 USD|
|Since start of Oct|92.47 USD|
|Forecast for Oct|131.20 USD|
|Last 7 days|29.83 USD|
|Last 30 days|92.47 USD|
|Total cost in timeframe|92.47 USD|

## By Service Name

|Service|Amount|
|---|---:|
|Amazon Elastic Compute Cloud - Compute|41.20 USD|
|Amazon Relational Database Service|22.75 USD|
|EC2 - Other|11.04 USD|

## By Region

|Region|Amount|
|---|---:|
|eu-west-1|80.12 USD|
|us-east-1|11.90 USD|

<sup>Generated at 2026-10-22 07:40:23 for AWS account `123456789012`</sup>

Excluded in the above sample, but it will also include mermaidjs diagrams as well.

Error handling

When the tool detects an exception, it will write this to the error stream and return with a -1 (shown as 255 by most shells). This can be used in scripts to detect if something went wrong. If you want to capture any errors as well, redirect the error stream to a different file:

aws-cost accumulatedCost -o markdown > cost.md 2>error.log

Common errors:

Error Fix
Failed to resolve AWS credentials Run aws login, aws sso login --profile <name> or aws configure, or pass --profile.
The AWS profile 'x' could not be found Check aws configure list-profiles.
AWS error (AccessDeniedException) Grant the permissions above and make sure Cost Explorer is enabled.
AWS error (DataUnavailableException) Cost Explorer was enabled recently; data becomes available within 24 hours.
Validation error on --filter Use DIMENSION=value or tag:Key=value.

Iterate over multiple accounts

The tool reports on the account of the credentials it uses. To report on several accounts, loop over your profiles:

for profile in dev test prod; do
    echo "Account: $profile"
    aws-cost accumulatedCost -o markdown --quiet --profile $profile
done

Or using PowerShell, appending all daily costs into a single CSV file:

$profiles = "dev", "test", "prod"
aws-cost accumulatedCost -o csv --quiet --profile $profiles[0] | Set-Content .\report.csv
$profiles | Select-Object -Skip 1 | ForEach-Object {
    aws-cost accumulatedCost -o csv --quiet --skipHeader --profile $_ | Add-Content .\report.csv
}

Using the --skipHeader parameter is important here, otherwise you will get a header for each account.

With AWS Organizations, it is usually easier (and cheaper) to run once against the management account and use the By Linked Account breakdown, or filter on a single member account:

aws-cost accumulatedCost --profile management --filter LINKED_ACCOUNT=123456789012

Is there cost involved?

Yes. Unlike the Azure Cost Management API, the AWS Cost Explorer API is billed per request: USD 0.01 per paginated request at the time of writing. The accumulatedCost command makes:

Request Count
GetCostAndUsage (daily totals) 1
GetCostForecast (only when the timeframe includes today) 0–1
GetCostAndUsage grouped by service, region, linked account 3

So a run costs about USD 0.04–0.05 (a bit more if results are paginated). Running it daily from a scheduled workflow costs roughly USD 1.50 per month. Cost Explorer data refreshes about once a day, so running it more often than every few hours gives little extra value.

Development

dotnet build aws-cost-cli.sln
dotnet test aws-cost-cli.sln
src/
├── Program.cs                 # Entry point, DI, command registration, AWS error handling
├── Commands/                  # Settings + commands (one folder per command)
│   └── AccumulatedCost/
├── CostApi/                   # Cost Explorer / STS integration (ICostRetriever)
├── OutputFormatters/          # Console, Json, Text, Markdown, Csv
└── Infrastructure/            # DI registrar/resolver, helpers
tests/AwsCostCli.Tests/        # xUnit + Moq + Shouldly

Credits

Based on azure-cost-cli by Michiel van Oudheusden, licensed under Apache-2.0. The Spectre.Console rendering helpers in src/OutputFormatters/SpectreConsole are taken from that project.

About

AWS Cost Explorer

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages