AWS Cost and Usage Report: The Ledger Behind Every AWS Bill

AWS Cost and Usage Report: The Ledger Behind Every AWS Bill

A deep, intermediate-level walkthrough of how the Cost and Usage Report captures, delivers, and structures line-item billing data — architecture, internals, operations, and the trade-offs that decide how a FinOps team should actually use it.

Picture a company’s monthly AWS invoice showing a single total: eighty-four thousand dollars. That number is true, but it is also nearly useless for making decisions — nobody can tell from it whether the spend came from an oversized database, an idle load balancer, or a genuinely necessary spike in traffic. The Cost and Usage Report exists to answer exactly that question. It breaks the one big number into millions of individual line items, one for nearly every hour of usage of nearly every resource, tagged with the account, service, region, and cost allocation tags that let a FinOps analyst trace spend back to a team, a project, or a single misconfigured instance. This tutorial goes beyond the basic “what is CUR” pitch and digs into how the report is actually generated, how its data is structured, how it scales to organizations with thousands of accounts, and how experienced teams avoid the mistakes that turn a promising cost-visibility project into an unqueried pile of files sitting in S3.

1Architecture & Components

The Cost and Usage Report is not a dashboard you log into — it is a data pipeline that deposits structured files into storage you control, and understanding that pipeline shape is the key to everything else.

The Core Building Blocks

A CUR definition tells AWS’s billing system what to generate, how often, and where to put it. Behind that simple definition sits AWS’s internal billing engine, which aggregates raw usage events from every service you consume, joins them against pricing and discount data, and writes the result as a structured dataset into an Amazon S3 bucket you own. From there, you are free to query the data with whatever analytics tool fits your organization, because the report itself is just files in object storage, not a locked-in proprietary system.

Definition

Report Configuration

Specifies the report name, time granularity, included data (resource IDs, tags), file format, and compression settings.

Destination

S3 Bucket

The report lands in an S3 bucket you designate, organized into a predictable folder structure by report name and billing period.

Format

File Format

Delivered as compressed CSV/GZIP for broad compatibility, or as Parquet for efficient columnar querying by analytics engines.

Schema

Manifest File

A JSON manifest accompanies each delivery, describing the column schema and listing the exact data files that make up that version of the report.

Query Layer

Athena / Redshift / QuickSight

Common downstream tools that read CUR data directly from S3, either via a Glue Data Catalog table or by loading it into a data warehouse.

Newer Option

Data Exports (CUR 2.0)

A newer delivery mechanism built on AWS Data Exports, offering more flexible, incremental, and standardized schema handling than the original CUR.

Simple Analogy

Think of the Cost and Usage Report as a supermarket’s detailed receipt versus its register total. The register total tells the shopper what they owe; the itemized receipt, listing every product, its unit price, and any discount applied, is what lets someone later figure out that half the bill came from produce that spoiled before it was used.

One Payer, One Report, Many Accounts

In an AWS Organizations setup with consolidated billing, a single CUR generated at the management account level can include line items from every linked member account, each clearly identified by its account ID. This is what allows a central finance or platform team to analyze spend across an entire organization from one dataset, rather than stitching together separate reports from dozens of individual accounts.

Production Example — Multi-Account SaaS Companies

SaaS companies running a separate AWS account per customer or per environment rely on a single organization-wide CUR to calculate the true infrastructure cost of serving each customer, feeding that data into per-customer profitability analysis.

flowchart TB
  subgraph Billing["AWS Billing Engine"]
    B1[Usage Aggregation]
    B2[Pricing & Discount Join]
  end
  subgraph Accounts["Linked Accounts"]
    A1[Account 1 Usage Events]
    A2[Account 2 Usage Events]
    A3[Account N Usage Events]
  end
  subgraph Delivery["Report Delivery"]
    S1[(S3 Bucket)]
    MF[Manifest File]
  end
  subgraph Consumers["Analytics Layer"]
    Q1[Athena]
    Q2[Redshift]
    Q3[QuickSight]
  end
  A1 --> B1
  A2 --> B1
  A3 --> B1
  B1 --> B2
  B2 --> S1
  B2 --> MF
  S1 --> Q1
  S1 --> Q2
  S1 --> Q3
        
FIG 1 — High-level flow from raw usage events to queryable cost data

2Internal Working

Understanding how a single line of usage becomes a single row in the report clarifies why the data behaves the way it does — including why numbers can shift slightly after the month closes.

From Usage Event to Line Item

Every AWS service emits internal usage records as resources are consumed — an EC2 instance running for an hour, a gigabyte transferred out of S3, a Lambda invocation completing. AWS’s billing engine collects these events, attaches the applicable pricing (on-demand rate, Reserved Instance discount, Savings Plan coverage, or negotiated enterprise discount), and produces one line item per unique combination of resource, usage type, and time period.

sequenceDiagram
  participant R as AWS Resource
  participant U as Usage Metering
  participant P as Pricing Engine
  participant C as CUR Generator
  participant S as S3 Bucket
  R->>U: Emit usage event (e.g. instance-hour)
  U->>P: Send raw usage record
  P->>P: Apply on-demand rate, RI/SP discount, tax
  P->>C: Priced line item
  C->>C: Aggregate into report file
  C->>S: Deliver updated CUR file + manifest
        
FIG 2 — How a single usage event becomes a priced line item in the report

Why the Report Updates Multiple Times

A CUR for the current month is not written once and left alone. AWS refreshes it multiple times a day throughout the month as new usage comes in, and continues refining it for a period after the month closes to account for late-arriving usage data, Reserved Instance and Savings Plan amortization calculations, and any billing corrections. This is why two queries against “the same” monthly report run a few days apart can return slightly different totals until the month is fully finalized.

Cost Allocation Tags Flowing Into the Report

Any cost allocation tag activated in the Billing console appears as its own column in the CUR, letting a line item for an EC2 instance carry through whatever team, project, or environment tag was applied to that resource. This is the mechanism that turns a report full of anonymous resource IDs into something a business can actually attribute spend against.

Simple Analogy

Cost allocation tags work like a receipt that lists not just “coffee, $4.50” but also which department’s expense account the coffee should be charged to, written right there on the same line, so accounting never has to guess later.

Production Example — Engineering Chargeback

Platform teams use tag-enriched CUR data to automatically charge back cloud spend to the specific engineering team that owns each tagged resource, replacing manual, error-prone spreadsheet-based cost allocation.

3Data Flow & Lifecycle

A single month’s report goes through a clear lifecycle from first draft to final, closed dataset, and knowing where a given billing period sits in that lifecycle matters for anyone building automated reports on top of it.

1

Report Definition Created

An administrator defines the report’s name, granularity (hourly, daily, or monthly), included columns, and target S3 bucket through the Billing console or API.

2

Initial Delivery

Within about a day of the current billing period beginning, the first version of that month’s report files land in the target S3 path.

3

Intra-Month Refresh

The report is updated multiple times daily throughout the month as new usage accrues, with each refresh overwriting the prior version’s files for that period.

4

Month-End Close

After the billing period ends, refreshes continue for several more days as late usage, credits, and Reserved Instance amortization settle.

5

Finalized Report

Once billing fully closes for that period, the report stabilizes and is treated as the authoritative historical record for that month.

6

Long-Term Retention

Historical report files remain in S3 under whatever lifecycle policy you configure, commonly moved to cheaper storage tiers as they age past active analysis needs.

Why Overwrite Behavior Matters for Pipelines

Because each refresh overwrites the files for that billing period rather than appending new ones, any downstream pipeline that partitions data by “file arrival time” instead of by billing period risks double-counting or losing data. Correctly built pipelines key off the billing period identified in the manifest, and re-process the full period’s files on each refresh rather than treating every file drop as strictly incremental.

!
Common Misunderstanding

Querying a report for the current, still-open month and treating the resulting total as final is a frequent source of confusion, since that number can still shift — usually upward — as late usage and reconciliation adjustments land over the following days.

4Advantages, Disadvantages & Trade-offs

CUR trades some simplicity for depth, and understanding that trade-off is essential before committing engineering time to build on top of it.

Advantages

  • Provides the most granular, resource-level cost and usage data AWS makes available, down to individual line items.
  • Data lands in S3 you own, so there is no vendor lock-in to a specific dashboard tool for analysis.
  • Cost allocation tags flow directly into the dataset, enabling precise chargeback and showback reporting.
  • Supports Parquet output, making it efficient to query at scale with Athena, Redshift Spectrum, or other columnar engines.
  • Covers Reserved Instance and Savings Plan amortization details needed for accurate effective-cost analysis.

Disadvantages / Trade-offs

  • Raw file volume for large organizations can be substantial, requiring deliberate partitioning and query optimization.
  • The schema is wide and detailed, with a learning curve for teams unfamiliar with billing terminology like amortized versus unblended cost.
  • Current-month data is provisional and can change until the billing period fully closes.
  • Building dashboards on top of raw CUR data requires engineering effort compared to using a pre-built tool like Cost Explorer.
  • Managing schema changes between CUR versions (or migrating to Data Exports) requires ongoing pipeline maintenance.
“Cost Explorer answers ‘how much did we spend’ quickly. The Cost and Usage Report answers ‘exactly why,’ at the cost of needing a query engine to ask it.”

When a Simpler Tool Is Enough

Organizations that only need high-level trend visibility — spend by service, by account, over time — are often well served by Cost Explorer’s built-in views without ever touching raw CUR data. CUR earns its complexity when the questions get specific: which exact resource drove last Tuesday’s spike, what is the true fully-loaded cost of a single customer’s workload, or how much of this month’s bill was covered by a specific Savings Plan.

5Performance & Scalability

CUR itself scales automatically with your usage — the real performance challenge is querying the resulting dataset efficiently as it grows into billions of rows for large organizations.

Why File Format and Partitioning Matter

A large organization’s hourly-granularity CUR can produce an enormous number of rows every month. Querying that volume as raw, uncompressed CSV files is slow and expensive for any analytics engine. Choosing Parquet output, combined with partitioning the Glue Data Catalog table by billing period, dramatically reduces the amount of data a typical query needs to scan, because columnar formats let the engine skip irrelevant columns and partitioning lets it skip irrelevant time ranges entirely.

Design ChoiceEffect on Query Performance
CSV/GZIP vs. ParquetParquet reduces scanned data volume significantly for column-selective queries
Hourly vs. daily granularityHourly multiplies row count roughly 24x; use only where truly needed
Partitioned Glue table by billing periodLets queries scan only relevant months instead of the entire history
Athena workgroup query result cachingSpeeds up repeated dashboard queries hitting the same data

Scaling to Very Large Organizations

Enterprises with thousands of linked accounts and hourly granularity can generate CUR datasets spanning many terabytes per year. At that scale, teams commonly load CUR data into a dedicated data warehouse such as Redshift, or use Athena with well-tuned partitioning, rather than querying S3 directly for every ad hoc report, trading some setup complexity for consistently fast query response times.

Hourly
Finest granularity option, useful for detailed anomaly investigation
Parquet
Recommended format for large-scale analytical querying
Multi-TB/yr
Realistic dataset size for large, multi-account enterprises

Production Example — FinOps Platform Teams

Large enterprises build internal FinOps platforms that continuously load partitioned CUR data into a warehouse, powering near-real-time cost anomaly detection dashboards used by dozens of engineering teams simultaneously.

6High Availability & Reliability

Reliability for CUR is less about uptime, since it is not an interactive service, and more about ensuring every billing period’s data is complete, durable, and reproducible.

Durability Comes From S3

Because report files are delivered into standard S3 storage, they inherit S3’s high durability characteristics automatically. The reliability question that actually matters for a CUR-based pipeline is not “will the files disappear” but “did my consuming pipeline correctly handle the refresh and finalization behavior described earlier.”

What You Are Responsible For

Bucket Policy

Prevent Accidental Deletion

Apply bucket policies and versioning on the destination S3 bucket so an accidental delete of report files does not erase historical billing data.

Cross-Region Copy

Backup for Critical Analysis

Organizations with strict continuity requirements replicate the CUR bucket to a second Region, protecting against a regional S3 disruption affecting cost visibility.

Pipeline Idempotency

Handle Refreshes Correctly

Downstream ETL jobs should be idempotent per billing period, safely reprocessing a period’s data on every refresh without creating duplicate rows.

Schema Watch

Track Manifest Changes

AWS occasionally adds new columns to the report; pipelines that hard-code a fixed schema should monitor the manifest for changes rather than assuming permanence.

i
Reliability Insight

Because the manifest file explicitly lists every data file belonging to a given report version, a well-built consumer always reads the manifest first rather than guessing which files in the S3 prefix are current, which avoids subtle bugs when old and new refreshes briefly coexist.

7Security

Billing data is sensitive in its own right — it reveals infrastructure scale, business growth patterns, and internal cost structure — so protecting the CUR bucket deserves the same rigor as any other confidential dataset.

Access Control on the Destination Bucket

The S3 bucket receiving CUR files should be locked down with a restrictive bucket policy limiting write access to the AWS billing service principal and read access to only the specific roles, teams, or analytics services that legitimately need it. Broad, organization-wide read access to a bucket containing detailed cost data unnecessarily exposes sensitive business information.

Encryption

Server-Side Encryption

Enabling default encryption on the destination bucket, using either S3-managed keys or a customer-managed KMS key, protects report files at rest.

IAM

Least-Privilege Query Roles

Analytics roles used by Athena or Redshift Spectrum to query CUR data should be scoped narrowly rather than reusing broad administrative roles.

Cross-Account

Controlled Sharing

When a central FinOps account needs to read a bucket owned by another account, a scoped cross-account bucket policy is preferable to duplicating credentials or files.

Audit

S3 Access Logging

Enabling access logging or CloudTrail data events on the bucket provides a record of who queried billing data and when, useful for internal audits.

SECURITY-PATTERN-01 Recommended
Context

A central FinOps team needs to give individual engineering teams visibility into only their own tagged spend, without exposing the full organization’s cost data.

Approach

Load the full CUR into a central warehouse, then expose team-scoped views or dashboards filtered by cost allocation tag, rather than granting direct query access to the raw, unfiltered dataset.

Outcome

Engineering teams get the granular cost visibility they need to manage their own spend, while sensitive organization-wide financial totals remain restricted to the finance and platform teams who need the full picture.

Simple Analogy

Restricting CUR bucket access is like keeping a company’s full financial ledger in the accounting office rather than pinned to a public bulletin board — individual departments still get their own budget summary, just not everyone else’s numbers alongside it.

8Monitoring, Logging & Metrics

Monitoring a CUR-based pipeline means watching both the health of the data pipeline itself and the cost signals the data reveals.

Pipeline Health Signals

A production-grade CUR pipeline typically monitors whether the expected manifest file arrives on schedule, whether the row counts for a refreshed period fall within an expected range, and whether any ETL job consuming the data fails or times out. An S3 event notification on the report prefix, feeding into an EventBridge rule, is a common way to trigger downstream processing automatically the moment a new report version lands.

Manifest Arrival
Primary signal that a new report refresh is ready to process
Row Count Delta
Useful sanity check between consecutive refreshes of the same period
EventBridge
Common trigger mechanism for automated CUR ingestion pipelines

Cost Signals Worth Alarming On

Beyond pipeline health, many teams build alerts directly from CUR-derived data: a sudden spend spike in a specific service or account, an untagged resource crossing a cost threshold, or Reserved Instance/Savings Plan utilization dropping below an efficient level. These alerts often complement, rather than replace, native tools like AWS Budgets and Cost Anomaly Detection.

!
Common Mistake

Building cost dashboards directly against the current, still-refreshing month without clearly labeling the data as provisional leads stakeholders to misinterpret a partial number as the final monthly total, prompting confusion when the figure later increases.

9Deployment & Cloud

Standing up a production CUR pipeline is primarily a data-engineering exercise built on a few well-understood AWS services working together.

A Typical Reference Architecture

A common pattern defines the CUR to deliver Parquet files into a dedicated S3 bucket, registers that data with an AWS Glue crawler to populate a Data Catalog table with billing-period partitions, and exposes the table to Amazon Athena for ad hoc SQL querying and to Amazon QuickSight for dashboarding. Larger organizations often add a step that loads the data into Amazon Redshift for more demanding, high-concurrency analytical workloads.

flowchart LR
  CUR[CUR Definition] --> S1[(S3 Bucket - Parquet)]
  S1 --> GC[Glue Crawler]
  GC --> DC[(Glue Data Catalog)]
  DC --> ATH[Athena Queries]
  DC --> RS[Redshift Spectrum / Load]
  ATH --> QS[QuickSight Dashboards]
  RS --> QS
        
FIG 3 — Reference pipeline from report definition to dashboard

Setting Up Multi-Account Reporting

In an AWS Organizations environment, the CUR is typically defined once in the management account with consolidated billing enabled, automatically including every linked account’s usage. Some organizations additionally replicate the resulting dataset into a dedicated, centrally-owned analytics account, keeping billing data access separate from the sensitive permissions the management account otherwise holds.

Choosing Between Legacy CUR and Data Exports

AspectLegacy CURData Exports (CUR 2.0)
Schema flexibilityFixed set of report versionsMore standardized, extensible schema options
Delivery modelFull refresh per billing periodDesigned for more consistent incremental handling
Best fitExisting pipelines already built around itNew pipelines and multi-report standardization needs

Production Example — Central Analytics Account Pattern

Large enterprises route CUR data from every business unit’s management account into one central analytics account dedicated purely to cost reporting, so finance can build a single, unified view across the entire company without needing broad access to any operational AWS account.

10Design Patterns & Anti-patterns

Certain pipeline designs consistently hold up as data volume and organizational complexity grow, while others create recurring, painful rework.

Pattern

Manifest-Driven Ingestion

Always read the manifest file to determine which data files belong to a given report version, rather than listing the S3 prefix and guessing.

Pattern

Partition by Billing Period

Partition the Glue Data Catalog table by year and month so queries naturally scope to the relevant time range and avoid full-history scans.

Pattern

Separate Raw and Curated Layers

Keep the raw CUR files untouched in one S3 location, and write cleaned, business-friendly transformed tables to a separate curated location for dashboards.

Pattern

Tag Governance Before Reporting

Enforce mandatory cost allocation tags on resources before relying heavily on tag-based chargeback reports, so the underlying data is actually attributable.

ANTI-PATTERN-01 Avoid
Problem

Treating every new file appearing in the CUR S3 prefix as strictly new, incremental data to append to a table.

Why It’s Harmful

Because refreshes overwrite a billing period’s data rather than appending to it, naive append-only ingestion produces duplicated or inconsistent totals for any period that has been refreshed more than once.

Correct Approach

Reprocess an entire billing period from its manifest on every refresh, replacing that period’s data in the curated table rather than blindly appending.

ANTI-PATTERN-02 Avoid
Problem

Choosing hourly granularity for every account and service by default, without evaluating whether daily granularity would meet the actual analysis need.

Why It’s Harmful

Hourly granularity multiplies row counts dramatically, driving up both storage and query costs for organizations that only ever analyze data at a daily or monthly level.

Correct Approach

Default to daily granularity for general reporting, and reserve hourly granularity for specific accounts or time windows genuinely under detailed cost investigation.

ANTI-PATTERN-03 Avoid
Problem

Granting every engineer in the organization direct query access to the raw, unfiltered CUR dataset.

Why It’s Harmful

The raw dataset exposes company-wide spend across every team and account, which is more visibility than most individual engineers need and can expose sensitive business scale information broadly.

Correct Approach

Provide scoped, tag-filtered views or dashboards to individual teams, reserving raw dataset access for the central FinOps or platform team responsible for the pipeline.

11Best Practices & Common Mistakes

Getting durable value out of CUR is less about the initial setup and more about the ongoing discipline of tagging, schema management, and stakeholder communication.

Best Practices

Practice

Standardize Tagging Early

Agree on a small, mandatory set of cost allocation tags — team, environment, project — before scaling CUR-based chargeback reporting across the organization.

Practice

Automate Schema Drift Detection

Have the ingestion pipeline compare each new manifest’s column list against the last known schema and alert on unexpected changes.

Practice

Clearly Label Provisional Data

Mark current-month figures as “in progress” in any dashboard so stakeholders do not mistake a still-refreshing total for the final number.

Practice

Reconcile Against the Console Periodically

Spot-check CUR-derived totals against the Billing console’s own summary to catch pipeline bugs before stakeholders do.

Common Mistakes

Mistake

Confusing Unblended and Amortized Cost

Using the wrong cost column for a given analysis — such as unblended cost when amortized cost is what’s needed to account for upfront Reserved Instance payments — produces misleading conclusions.

Mistake

Ignoring Untagged Resources

Building chargeback reports that silently exclude untagged spend understates real costs and hides exactly the resources most in need of governance attention.

Mistake

Building One-Off Queries Instead of a Curated Layer

Repeatedly writing ad hoc SQL against raw CUR data instead of building a stable, curated table wastes effort and produces inconsistent results across teams.

Mistake

Never Revisiting Report Configuration

Leaving granularity, included columns, and included accounts unchanged for years, even as the organization’s structure and reporting needs evolve significantly.

12Real-world & Industry Examples

Seeing how different organizations use CUR clarifies which of its capabilities matter most in each context.

SaaS — Per-Customer Cost of Goods Sold

Multi-tenant SaaS companies join CUR data with internal customer-to-account mapping tables to calculate the true infrastructure cost of serving each customer, directly informing pricing and margin decisions.

Enterprise IT — Departmental Chargeback

Large enterprises use tag-enriched CUR data to bill internal departments for their actual cloud consumption, replacing flat, estimated IT cost allocations with usage-based figures.

FinOps Teams — Reserved Instance and Savings Plan Optimization

FinOps practitioners analyze amortized cost and coverage columns in CUR data to identify underutilized commitments and recommend adjustments before renewal decisions are made.

Consulting & Managed Service Providers — Client Billing

Managed service providers running client workloads in linked AWS accounts use CUR data as the factual basis for client invoices, ensuring billed amounts trace directly back to actual, itemized usage.

Regulated Industries — Cost Audit Trails

Organizations in regulated sectors retain historical CUR data as part of demonstrating exactly what infrastructure was provisioned and billed during a given audit period.

13Frequently Asked Questions

Q1Where does the Cost and Usage Report actually get delivered?

To an Amazon S3 bucket you designate when creating the report definition, organized by report name and billing period, alongside a manifest file describing the delivered data files.

Q2Why does the total for the current month keep changing?

The current month’s report refreshes multiple times a day and continues updating for several days after the period closes, as late usage, credits, and Reserved Instance or Savings Plan amortization are finalized.

Q3Can one report include usage from every account in an organization?

Yes, when generated from the management account of an AWS Organizations setup with consolidated billing enabled, the report includes line items from every linked member account.

Q4What is the difference between unblended and amortized cost columns?

Unblended cost reflects the cost as it actually occurred on that line item, while amortized cost spreads upfront Reserved Instance or Savings Plan payments evenly across the commitment’s term, giving a more accurate ongoing cost picture.

Q5Which file format should be chosen for large-scale querying?

Parquet is generally recommended for large datasets because its columnar structure lets query engines like Athena scan only the columns and partitions actually needed, reducing cost and latency compared to CSV.

Q6Do untagged resources still appear in the report?

Yes, every line item appears regardless of tagging, but its cost allocation tag columns are simply empty, which is why tag governance matters for accurate chargeback reporting.

14Summary and Key Takeaways

The Cost and Usage Report turns a single opaque AWS invoice total into a granular, queryable dataset covering nearly every billable event across an organization’s accounts. Its architecture delivers structured files into S3 you control, its lifecycle refreshes throughout the month before settling into a finalized historical record, and its value depends entirely on deliberate design choices — the right granularity, the right file format, disciplined tagging, and a pipeline built around the manifest rather than guesswork. Security and access control matter because billing data reveals sensitive business information, and the patterns and anti-patterns above reflect lessons learned across SaaS, enterprise IT, FinOps, consulting, and regulated organizations that rely on CUR as the factual foundation of their cost management practice.

Key Takeaways

  • CUR is a data pipeline, not a dashboard. It delivers structured files to S3 you own, leaving the choice of analytics tool entirely up to you.
  • Data refreshes and finalizes over time. Current-month totals are provisional until the billing period fully closes.
  • Cost allocation tags are what make the data attributable. Without disciplined tagging, chargeback reports understate or misattribute real spend.
  • Always ingest via the manifest, not the raw file listing. This avoids duplication and confusion during report refreshes.
  • File format and partitioning drive query cost and speed. Parquet plus billing-period partitioning is the standard high-performance combination.
  • Access to raw billing data should be scoped. Central teams should expose filtered views rather than granting broad access to the full dataset.
  • Know which cost column answers your question. Unblended versus amortized cost tell meaningfully different stories about the same spend.