CloudBurn Cloud

Usage Assumptions Schema

Full reference for .cloudburn/usage-assumptions.json — fields, units, precedence, free tier, and account usage for CloudBurn cost reports.

Some AWS services bill by workload, not by declared capacity. A bucket, queue, or topic can appear in a diff while the diff says nothing about storage, request volume, or data transfer. CloudBurn prices S3, SQS, and SNS usage from monthly assumptions that live in your repository, and every assumed cost in the report is labeled as an assumption, never presented as a fact.

This page is the schema reference for that file: .cloudburn/usage-assumptions.json at the root of your repository.

How the file reaches CloudBurn

The CloudBurn GitHub App never reads repository files. The aws-cdk-diff-pr-commenter and terraform-plan-pr-commenter actions read .cloudburn/usage-assumptions.json at the pull request head and base commits and embed both snapshots into the diff comment inside a collapsed block. The app prices the head snapshot as the current state and the base snapshot as the previous state, so a pull request that only edits assumptions still shows its real cost delta.

Three producer rules to know:

  • A file over 65,536 bytes is not embedded; the app reports it as a configuration error.
  • Invalid JSON, duplicate JSON keys, or unknown fields fail the whole assumptions block with one explicit error. CloudBurn flags the estimate as incomplete rather than silently pricing without your numbers.
  • Repositories without the file get the same diff comment and cost report as before — assumptions are opt-in.

Top-level fields

{
  "schemaVersion": 2,
  "revision": "2026-07-01",
  "freeTier": "disabled",
  "accountContext": {},
  "organizationDefaults": {},
  "repositoryDefaults": {},
  "resourceTypeDefaults": {},
  "resources": {}
}
FieldTypePurpose
schemaVersion1 or 2Required. Use 2; accountContext and free-tier handling need it.
revisionstring or numberOptional label for your own change tracking.
freeTier"enabled"/"disabled"Free-tier policy. Defaults to "disabled". Also accepted per layer and per resource.
accountContextobjectAccount-wide usage and remaining free-tier allowances. Schema v2 only.
organizationDefaultsobjectBroadest defaults, explicitly copied into the repository.
repositoryDefaultsobjectRepository-wide defaults.
resourceTypeDefaultsobjectDefaults per CloudFormation resource type, such as AWS::S3::Bucket.
resourcesobjectPer-resource overrides keyed by the stable IaC address.

Supported resource types for usage pricing: AWS::S3::Bucket, AWS::SQS::Queue, and AWS::SNS::Topic.

Resolution precedence

A value resolves from the narrowest layer that supplies it. The layers below are listed in application order from broadest to narrowest — when several define the same field, the last (narrowest) matching layer wins:

  1. organizationDefaults — broadest
  2. repositoryDefaults
  3. resourceTypeDefaults["AWS::S3::Bucket"]
  4. resources["<address>"] — narrowest, always wins

Keys under resources are stable IaC addresses: the CDK construct path such as StorageStack/ReportsBucket, or the Terraform address such as module.storage.aws_s3_bucket.reports. Wildcard selectors are rejected. A bare CDK construct name without its stack works only while it matches exactly one changed resource; an ambiguous selector fails the whole block. The report attributes every assumed component to the scope and field that supplied its quantity.

Quantities and units

Every quantity is monthly and carries an explicit unit. A bare number uses the measure's canonical unit; an object form converts to it:

{ "value": 2, "unit": "TB" }
MeasureCanonical unitAccepted units
storageGB-MoGB-Mo, GB-month, GB, TB-Mo, TB
requestsrequestsrequests, thousand-requests, k-requests, million-requests
dataTransferGBGB, GB-Mo, TB, TB-Mo
countobjectsobjects, thousand-objects, million-objects

Unknown units, negative values, and any period other than "month" are rejected.

S3 fields

Set these under an s3 group at any layer. A missing field affects only its own cost component.

FieldMeasurePrices
s3.storage.standardGbMonthstorageStandard storage (carries the opt-in free tier)
s3.storage.standardIaGbMonthstorageStandard-IA storage
s3.storage.oneZoneIaGbMonthstorageOne Zone-IA storage
s3.storage.glacierIrGbMonthstorageGlacier Instant Retrieval storage
s3.storage.glacierFlexibleGbMonthstorageGlacier Flexible Retrieval storage
s3.storage.deepArchiveGbMonthstorageGlacier Deep Archive storage
s3.storage.intelligentTieringFaGbMonthstorageIntelligent-Tiering frequent-access storage
s3.requests.tier1requestsPUT, COPY, POST, and LIST requests
s3.requests.tier2requestsGET, SELECT, and all other requests
s3.lifecycleTransitions.standardIarequestsTransitions to Standard-IA
s3.lifecycleTransitions.oneZoneIarequestsTransitions to One Zone-IA
s3.lifecycleTransitions.glacierIrrequestsTransitions to Glacier Instant Retrieval
s3.lifecycleTransitions.intelligentTieringrequestsTransitions to Intelligent-Tiering
s3.lifecycleTransitions.glacierFlexiblerequestsTransitions to Glacier Flexible Retrieval
s3.lifecycleTransitions.deepArchiverequestsTransitions to Glacier Deep Archive
s3.retrieval.glacierIrGbdataTransferGlacier Instant Retrieval data retrieval
s3.retrieval.glacierFlexibleGbdataTransferGlacier Flexible Retrieval data retrieval
s3.retrieval.deepArchiveGbdataTransferGlacier Deep Archive data retrieval
s3.dataTransfer.outToInternetGbdataTransferOutbound data transfer to the internet
s3.monitoring.intelligentTieringObjectscountIntelligent-Tiering monitoring, billed per object
s3.monitoring.objectscountFallback monitored-object count, used when Intelligent-Tiering is configured but the specific field above is not set

CloudBurn never infers usage from existence: it does not guess request volume from object counts or stored bytes from a bucket's presence. Two fields stay intentionally ambiguous and report as unknown: s3.dataTransfer.gb (no direction) and the legacy s3.requests.lifecycleTransition (AWS prices each transition destination differently).

SQS fields

FieldMeasurePrices
sqs.requestsrequestsStandard or FIFO billable request units per month

The adapter picks the Standard or FIFO price from the queue's declared FifoQueue property. Supply already-normalized AWS billable request units: account for batching, then round each payload up in 64 KB chunks. One API action with a 256 KB payload contributes four request units. All queues share one sqs.requests account pool and free-tier pool, and Standard requests claim the shared allowance before FIFO requests so resource order cannot change the total.

SNS fields

FieldMeasurePrices or result
sns.publishedMessagesrequestsStandard or FIFO billable publish request units
sns.deliveries.httprequestsStandard HTTP/S billable delivery units
sns.deliveries.emailrequestsStandard email billable delivery units
sns.deliveries.sqsrequestsStandard or FIFO SQS billable delivery units
sns.deliveries.lambdarequestsStandard Lambda billable delivery units
sns.deliveries.mobilePushrequestsStandard mobile push billable delivery units
sns.deliveries.messagesrequestsAmbiguous without a delivery protocol; reported as unknown
sns.deliveries.smsrequestsUnsupported — SMS pricing needs destination-specific inputs; stays unknown

These fields also take normalized billable units: apply publish batching first, then round Standard publish and non-SMS delivery payloads up in 64 KB chunks. The adapter selects Standard or FIFO pricing from the topic's declared FifoTopic property. FIFO topics support SQS delivery pricing only; FIFO payload-volume charges and data transfer remain explicitly unknown until payload-size assumptions are supported.

Account usage and graduated tiers

AWS applies graduated pricing tiers across an account, not per resource. Put the billable usage that already occupies each tier under accountContext.usage, and CloudBurn starts the changed resources after that quantity, advancing one shared pool per account as it prices each resource.

Account poolCanonical unit
s3.storage.standard, s3.storage.standardIa, s3.storage.oneZoneIaGB-Mo
s3.storage.glacierIr, s3.storage.glacierFlexible, s3.storage.deepArchiveGB-Mo
s3.storage.intelligentTieringFaGB-Mo
s3.requests.standardTier1, s3.requests.standardTier2requests
s3.lifecycleTransitions.<destination>requests
s3.retrieval.glacierIr, s3.retrieval.glacierFlexible, s3.retrieval.deepArchiveGB
s3.monitoring.intelligentTieringobjects
awsDataTransfer.outboundInternetGB
sqs.requestsrequests
sns.requests.standardrequests
sns.deliveries.http, sns.deliveries.email, sns.deliveries.mobilerequests

For example, 100 GB of new Standard storage after 51,150 GB of existing usage spans 50 GB in the first tier and 50 GB in the second. A graduated component stays unknown when its account pool is missing — CloudBurn doesn't guess where your account sits in the tier.

Free tier

CloudBurn doesn't guess whether your account still has free allowance. Set "freeTier": "enabled" at the file, layer, or resource scope, then provide the remaining allowance under accountContext.remainingFreeTier:

{
  "schemaVersion": 2,
  "freeTier": "enabled",
  "accountContext": {
    "usage": { "s3.storage.standard": 0 },
    "remainingFreeTier": { "s3.storage.standard": 5 }
  }
}

The remaining 5 GB is consumed once across all buckets in a stable resource order. If free tier is enabled but a pool's remaining allowance is missing, that component stays unknown. Free-tier pools exist for sqs.requests, sns.requests.standard, sns.deliveries.http, sns.deliveries.email, sns.deliveries.mobile, s3.storage.standard, s3.requests.standardTier1, s3.requests.standardTier2, and awsDataTransfer.outboundInternet.

Validation limits

LimitValue
Maximum file size65,536 bytes
Maximum nesting depth8
Maximum key length128
Maximum resources selectors500
Maximum resource-type selectors200
Maximum fields per profile300

Any violation, duplicate JSON key, or unknown field fails the whole assumptions block with one explicit configuration error in the cost report.

Complete example

{
  "schemaVersion": 2,
  "revision": "2026-07-01",
  "freeTier": "disabled",
  "accountContext": {
    "usage": {
      "s3.storage.standard": 50000,
      "s3.requests.standardTier1": 1000000,
      "s3.requests.standardTier2": 5000000,
      "awsDataTransfer.outboundInternet": 10000
    }
  },
  "repositoryDefaults": {
    "s3": { "requests": { "tier2": { "value": 5, "unit": "million-requests" } } }
  },
  "resourceTypeDefaults": {
    "AWS::S3::Bucket": {
      "s3": { "storage": { "standardGbMonth": 100 } }
    }
  },
  "resources": {
    "StorageStack/ReportsBucket": {
      "s3": {
        "storage": { "standardGbMonth": { "value": 2, "unit": "TB" }, "deepArchiveGbMonth": 10000 },
        "requests": { "tier1": { "value": 200, "unit": "thousand-requests" } },
        "lifecycleTransitions": { "deepArchive": { "value": 50, "unit": "thousand-requests" } },
        "retrieval": { "deepArchiveGb": 50 },
        "dataTransfer": { "outToInternetGb": 1000 }
      }
    }
  }
}

Here StorageStack/ReportsBucket overrides the resource-type storage default and adds archival storage, destination-specific transitions, retrieval, and outbound transfer. Every other AWS::S3::Bucket in the diff inherits 100 GB of Standard storage and 5 million monthly Tier 2 requests from the broader layers.

What's next

Read thisTo learn
GitHub App overviewHow the app turns diff comments into cost reports
aws-cdk-diff-pr-commenterThe action that embeds assumptions for CDK diffs
terraform-plan-pr-commenterThe action that embeds assumptions for Terraform plans