CostMonStart free

Reference

The AWS Bill Decoder

Every cryptic line item on an AWS bill, decoded: what it means, why it spikes, and how to cut it — each one verified against official AWS documentation, not guessed.

Last updated 50 line items across 7 categories

Where to find these on your own bill

  1. Open Cost Explorer and set “Group by” to Usage type (not just Service) — that field is exactly what this page decodes.
  2. For detail beyond what Cost Explorer's UI shows, turn on a Cost and Usage Report (CUR) and look at the lineItem/UsageType column — it's the identical string.
  3. If the list is long, filter to a single service first, then group by Usage type within it to see which specific charge is driving that service's cost.
  4. Don't recognize a code on your own bill? Paste it into CostMon's search (⌘K) or the filter below — most of what actually shows up on real AWS bills is covered here.

How to read a usage type

Most of the confusion in a usage-type string comes down to a small, consistent grammar — a region code, an optional inter-region pair, a direction, and sometimes an instance-type suffix.

(no prefix)

Generally us-east-1 (N. Virginia) — the default region for the classic "AWS Data Transfer" family (DataTransfer-Out-Bytes, DataTransfer-Regional-Bytes). Every other region gets its short code prepended instead. Not universal, though: some services (Elastic Load Balancing, Transit Gateway, Public IPv4) prefix us-east-1 explicitly as USE1- too, so check which service a code belongs to before assuming.

USE1 / USE2

us-east-1 (N. Virginia) / us-east-2 (Ohio)

USW1 / USW2

us-west-1 (N. California) / us-west-2 (Oregon)

EU / EUW2 / EUW3

eu-west-1 (Ireland — note the bare "EU", no trailing "1") / eu-west-2 (London) / eu-west-3 (Paris)

EUC1 / EUN1

eu-central-1 (Frankfurt) / eu-north-1 (Stockholm)

APN1 / APN2 / APN3

ap-northeast-1 (Tokyo) / ap-northeast-2 (Seoul) / ap-northeast-3 (Osaka)

APS1 / APS2 / APS3

ap-southeast-1 (Singapore) / ap-southeast-2 (Sydney) / ap-south-1 (Mumbai)

USE1-USW2- (a paired prefix)

An inter-region transfer between the two named regions — the first is the source, the second is the destination. Only the source region's outbound leg is actually billed; the destination's inbound leg is $0.

-AWS-Out-Bytes / -AWS-In-Bytes

Outbound (billed) vs. inbound (free) data transfer between AWS regions, or between AWS and the public internet.

:instanceType suffix

The specific instance type or size a charge applies to, e.g. BoxUsage:m5.large — one line per distinct type actually in use.

Worked example

USE1-USW2-AWS-Out-Bytes
  • USE1 — the source region: us-east-1
  • USW2 — the destination region: us-west-2
  • AWS — the transfer stayed inside AWS's network, not the public internet
  • Out — this is the outbound, billed leg, from the source region's side
  • Bytes — metered per byte (GB), not per hour or per request

This exact line only appears on the us-east-1 side of the transfer. The us-west-2 side shows the free companion line, USW2-USE1-AWS-In-Bytes, for the same traffic.

Filter line items

Data transfer & networking

The single biggest mystery bucket on most bills — internet egress, cross-AZ, NAT gateways, and the region-code grammar behind all of it.

DataTransfer-Out-BytesAmazon EC2

Internet data transfer out

You are being charged per gigabyte for data leaving an AWS region to the public internet.

This is the single most common line item on almost every AWS bill: any response an EC2 instance, load balancer, or API sends back to a browser, mobile app, or external API counts as egress. It often shows up bundled under "EC2-Other" in Cost Explorer even when the traffic originated from another service that routes through EC2-managed infrastructure.

Spikes usually trace to a new public-facing feature (video/image delivery, large API payloads, backups pushed to an external destination), a bot or scraping wave hitting an unprotected endpoint, or serving large static assets directly instead of through a CDN.

How to cut it

  • Put CloudFront (or another CDN) in front of anything served repeatedly to the public internet — CDN egress pricing is lower than direct-to-internet, and cached hits avoid origin egress entirely.
  • Compress payloads (gzip/brotli) and move large downloadable files to S3 with appropriate storage/lifecycle tiers rather than serving from compute instances.
  • Check for unintended public exposure (an open bucket, an unauthenticated endpoint) if the increase isn't tied to a known feature launch.
  • Track usage against the account-wide free-tier allotment and the volume tiers below it so pricing assumptions match the actual tier.

$0.09 per GB (first 10 TB/month tier) — us-east-1, applies after the AWS-wide free tier; as of 2026-07

Source: AWS docs →
USE1-USW2-AWS-Out-BytesAmazon EC2

Inter-region data transfer

You are being charged for data sent from one AWS region (here, us-east-1) to a different AWS region (here, us-west-2).

This appears whenever resources in different regions talk to each other: cross-region database replication or read replicas, multi-region S3 replication, a service in one region calling an API hosted in another, or disaster-recovery jobs.

It's confusing because AWS emits two line items for every transfer — a "{Source}-{Dest}-AWS-Out-Bytes" on the source side and a "{Dest}-{Source}-AWS-In-Bytes" on the destination side — but only the outbound side from the source region actually carries a charge; the inbound side is $0.

How to cut it

  • Co-locate chatty services and their data stores in the same region wherever latency or compliance requirements allow.
  • Use cross-region replication and read replicas deliberately (for DR/compliance), not as a default multi-region pattern, since every byte is billed on the sending side.
  • For multi-region active-active architectures, weigh whether a global accelerator, private connectivity, or regional caching reduces total cross-region volume.
  • Group by Usage type in Cost Explorer to see exactly which region pair is generating the charge before optimizing.
Source: AWS docs →
DataTransfer-Regional-BytesAmazon EC2

Cross-AZ (regional) data transfer

You are being charged for data moving between Availability Zones within the same AWS region — billed on both the sending and the receiving side.

Same-AZ traffic over private IPs is free, but the moment two communicating resources land in different AZs, every byte is billed twice: once as the sender's outbound leg and once as the receiver's inbound leg.

Common triggers: an auto-scaled fleet or Kubernetes cluster spreading instances across AZs for high availability, a NAT gateway that exists in only one AZ while resources run in others, or chatty microservice/service-mesh traffic that isn't AZ-aware.

How to cut it

  • Keep a NAT gateway (or gateway endpoint) in every AZ you use so traffic doesn't cross AZ boundaries just to reach the internet or an AWS service.
  • Make AZ-aware routing/affinity a first-class concern in service mesh or load-balancer configuration so requests prefer same-AZ targets.
  • For chatty replicated/clustered workloads, weigh the availability benefit of spreading across AZs against the steady-state cross-AZ transfer cost.
  • Use flow logs alongside Cost Explorer's regional-transfer totals to identify which resource pairs are generating the volume — the billing data alone won't show you that.

$0.01 per GB, in each direction — us-east-1; billed as two separate $0.01/GB charges (in + out) for each transfer; as of 2026-07

Source: AWS docs →
NatGateway-BytesAmazon VPC

NAT gateway data processing

You are being charged per gigabyte for every byte that passes through your NAT gateway, on top of its flat hourly uptime charge and on top of any standard data-transfer charge the traffic would incur anyway.

NAT gateways are the default egress path for private-subnet resources, so anything a private instance, a task, or a function does over the internet — pulling container images, calling third-party APIs, downloading OS/package updates — is metered here, often invisibly to the engineer who wrote the code.

The classic spike is container image pulls: registry layers, base OS images, and CI/CD artifact downloads routed through NAT can dwarf actual application traffic, especially in clusters with frequent deploys or aggressive auto-scaling.

How to cut it

  • Add VPC gateway endpoints for S3 and DynamoDB (no hourly or per-GB charge) and interface endpoints for other AWS services so that traffic never touches the NAT gateway.
  • Cache container base images and dependencies in-region rather than re-pulling from the internet on every deploy or scale event.
  • Run one NAT gateway per AZ (not one shared gateway) to avoid stacking cross-AZ charges on top of NAT processing charges.
  • For high-volume, latency-tolerant batch egress, evaluate whether a self-managed alternative is materially cheaper at your traffic volume.

$0.045 per GB processed — us-east-1; separate from the flat $0.045/hour NAT gateway uptime charge and from any standard data-transfer charge on the same bytes; as of 2026-07

Source: AWS docs →
PublicIPv4:InUseAddressAmazon VPC

Public IPv4 address charge

You are being charged hourly for every public IPv4 address you hold — whether it's actively attached and serving traffic, or allocated but unattached and idle.

AWS began charging for all public IPv4 addresses on February 1, 2024 — previously only "extra"/idle Elastic IPs were charged. This now covers the default public IP on every internet-facing instance, every Elastic IP, NAT gateway public IPs, and public IPs on AWS-managed resources, not just Elastic IPs.

Bills spike when accounts accumulate unattached Elastic IPs left over from decommissioned instances, or when a large fleet of instances or NAT gateways each get their own public IP instead of sharing egress through fewer public endpoints.

How to cut it

  • Release Elastic IPs that aren't attached to a running resource — they cost the same rate whether idle or in use, so idle ones are pure waste.
  • Move private-subnet workloads behind a NAT gateway (shared public IP) instead of giving each instance its own public IP.
  • Use a load balancer or CDN in front of a fleet instead of assigning public IPs to individual instances.
  • Audit across accounts with Cost Explorer filtered to this usage type to find and reclaim unused allocations.

$0.005 per hour per address — us-east-1 (uniform across commercial AWS regions); identical whether the address is in-use or idle; as of 2026-07

Source: AWS docs →
VpcEndpoint-BytesAmazon VPC

VPC interface endpoint (PrivateLink)

You are being charged an hourly fee per endpoint per Availability Zone, plus a per-gigabyte fee for data processed through an interface VPC endpoint (AWS PrivateLink).

This appears when you've deliberately added interface endpoints to avoid NAT gateway or internet routing for AWS-service traffic, or when a third-party product exposes itself via PrivateLink.

It surprises people two ways: the endpoint itself has an always-on hourly cost per AZ even at zero traffic, and teams sometimes deploy endpoints redundantly (one per AZ per service, per account) without realizing the hourly costs multiply.

How to cut it

  • Prefer gateway endpoints (S3, DynamoDB), which have no hourly or per-GB charge, over interface endpoints when the target service supports both.
  • Consolidate interface endpoints centrally in a shared-services VPC instead of duplicating the same endpoint in every account/VPC.
  • Remove endpoints for services no longer in active use — the hourly charge accrues regardless of traffic.
  • Compare the endpoint's hourly + per-GB cost against the NAT gateway cost it replaces; at low traffic volumes a NAT gateway can occasionally be cheaper than several redundant endpoints.
Source: AWS docs →
TransitGateway-BytesAWS Transit Gateway

Transit Gateway attachment and data processing

You are being charged an hourly fee for each attachment (VPC, VPN, Direct Connect, peering) connected to your Transit Gateway, plus a per-gigabyte fee for data processed through it.

Transit Gateway is the common hub-and-spoke pattern for connecting many VPCs, accounts, and on-prem networks, so its cost scales with both how many VPCs you've attached (hourly, per attachment) and how much traffic actually flows through the hub (per GB).

Costs balloon in large multi-account organizations as more accounts/VPCs are onboarded to a shared Transit Gateway, or when high-volume, chatty services route large data volumes through the hub instead of communicating more directly.

How to cut it

  • Use cost allocation tags on Transit Gateway attachments to see which team, account, or workload is driving hourly and data-processing charges.
  • For very high-volume point-to-point paths between two VPCs, consider direct VPC peering (no per-GB processing fee) instead of routing that traffic through Transit Gateway.
  • Remove attachments for decommissioned VPCs/accounts — the hourly charge continues until the attachment is explicitly deleted.
  • Right-size the topology: not every VPC needs a Transit Gateway attachment if it only talks to one or two other VPCs.
Source: AWS docs →
LoadBalancerUsageElastic Load Balancing

Load balancer hourly usage and LCU charge

You are being charged an hourly rate for each load balancer provisioned, plus a rate per Load Balancer Capacity Unit (LCU) consumed — LCUs are driven by whichever dimension (new connections, active connections, processed bytes, or rule evaluations) is highest that hour, not by a simple sum.

The flat hourly charge is predictable, but LCUs are the confusing part: AWS bills on the single highest-consuming dimension per hour, so a spike in new-connection rate or in processed bytes can drive cost up even if the other dimensions look normal.

Bills also climb simply from running more load balancers than needed — one per microservice or environment instead of consolidating with listener rules or path-based routing on shared load balancers.

How to cut it

  • Consolidate multiple services behind fewer load balancers using host- or path-based routing rules instead of provisioning one per service.
  • Investigate which LCU dimension is driving cost via CloudWatch metrics rather than assuming it's raw traffic volume.
  • Tune client connection behavior (keep-alives, connection pooling) to avoid unnecessary new-connection churn.
  • Delete idle/unused load balancers left over from decommissioned environments — the hourly charge accrues regardless of traffic.
Source: AWS docs →
US-DataTransfer-Out-BytesAmazon CloudFront

CloudFront data transfer and requests

You are being charged per gigabyte for content CloudFront serves from its edge locations to end users, plus a per-10,000-requests charge, with rates varying by the edge-location group (US, EU, AP, and so on) that served the request.

This looks similar to plain internet egress on the bill but is a distinct, usually cheaper, product line keyed off the edge location that answered the request rather than the origin's AWS region — so the prefix here is a broad geography code, not the fine-grained region codes used elsewhere.

Costs climb with cache-miss rate (uncacheable or short-TTL dynamic content forces more origin fetches), high request-per-second traffic from bots or scrapers, and serving traffic from higher-cost edge-location groups rather than cheaper tiers.

How to cut it

  • Increase cache hit ratio with longer TTLs and cache keys that don't over-fragment the cache.
  • Use a price-class restriction to serve only from lower-cost edge-location regions if global reach isn't required.
  • Enable compression and right-size assets at origin to reduce bytes served per request.
  • Separate cacheable GET/HEAD traffic from proxied write traffic in your monitoring, since proxied requests to origin can't benefit from caching.
Source: AWS docs →

Compute

EC2, Fargate, EKS, and Lambda — what you're actually paying for per hour, per GB, and per invocation.

BoxUsage:m5.largeAmazon EC2

On-Demand instance hours

The hourly running time of an On-Demand EC2 instance of the given type, in the given region — the base compute rate before other EC2 charges (storage, data transfer) are added.

This is usually the largest line on an EC2-heavy bill: every running On-Demand instance generates one BoxUsage row per instance type per region, per hour. A spike usually means more instances, larger instance types, or instances left running (forgotten dev/test boxes, autoscaling that scaled up and never fully scaled back down).

It also appears for managed services that run on EC2 under the hood, so a fleet-size change in a managed service can show up here too.

How to cut it

  • Buy Savings Plans or Reserved Instances for steady-state baseline usage — the BoxUsage line stays but the effective rate drops.
  • Right-size instance types using utilization recommendations rather than guessing.
  • Schedule or auto-stop non-production instances outside business hours.
  • Audit for orphaned instances — stopped-but-not-terminated, or running with no real traffic.
Source: AWS docs →
SpotUsage:m5.largeAmazon EC2

Spot instance hours

The hourly running time of an EC2 Spot Instance of the given type, billed at the fluctuating Spot market price instead of the fixed On-Demand rate.

Spikes when Spot capacity gets scarce and the market price rises, or when a workload scales out more Spot capacity — a batch-job burst, or an Auto Scaling group configured to prefer Spot.

Because Spot price varies by instance type, AZ, and time, the same fleet size can cost noticeably more from one week to the next with no change in usage volume.

How to cut it

  • Diversify across multiple instance types/families and AZs so the fleet draws from a deeper capacity pool instead of one scarce type.
  • Use a capacity-optimized allocation strategy to reduce interruption-driven relaunch churn.
  • Configure a mixed-instances policy with automatic fallback to a different pool (or On-Demand) instead of retrying the same one.
Source: AWS docs →
HeavyUsage:m5.largeAmazon EC2

Reserved Instance recurring fee

The recurring charge for a Reserved Instance you've already committed to — billed whether or not a matching instance is actually running that hour.

Confusing because it keeps appearing even after you stop using the matching instance type: an RI is a billing commitment, not a resource, so this line keeps charging for the full term regardless of whether matching usage shows up that hour.

"Heavy" is a holdover from AWS's early Light/Medium/Heavy Utilization RI options; the label stuck as the internal billing string even though AWS replaced that customer-facing naming with upfront-payment options years ago.

How to cut it

  • Only reserve capacity for genuinely steady-state workloads — not anything that might get right-sized or decommissioned mid-term.
  • Prefer regional (not zonal) scope and size-flexible instance families so the reservation can apply across more of the running fleet.
  • Watch for reservations no longer matching any usage, then modify or sell them rather than letting them run out unused.
Source: AWS docs →
UnusedBox:m5.largeAmazon EC2

Unused Capacity Reservation

The instance-hours of an On-Demand Capacity Reservation that were held open but never had an instance launched into them — billed at the full On-Demand rate for empty, reserved slots.

Appears whenever a Capacity Reservation is sized larger than the instances actually running against it — for example, ten slots reserved in an AZ for a launch event, but only two in use; the other eight bill as unused capacity every idle hour.

Easy to miss because it's a distinct usage type from the reservation itself and from any Reserved Instance discount — Capacity Reservations guarantee capacity but carry no billing discount of their own, so idle slots cost full price.

How to cut it

  • Size Capacity Reservations to actual peak concurrent instance count, not a padded estimate.
  • Scope reservations to the exact window capacity is needed (a launch event, a DR test) and delete them afterward.
  • Monitor reservation utilization to alert on reservations sitting persistently under-used.
Source: AWS docs →
DedicatedUsage:m5.largeAmazon EC2

Dedicated Instance hours

The hourly running cost of an EC2 instance launched with dedicated tenancy — single-tenant physical hardware, billed at a premium over the same instance type's shared-tenancy rate, plus a flat per-region hourly fee if any dedicated instance runs in that region.

Shows up when an instance, AMI, or an entire VPC's default tenancy is set to "dedicated" — often for compliance or licensing reasons — rather than "default"; one mistaken VPC-level tenancy setting can push every instance launched into it onto this pricier line without anyone noticing.

It's a different billing line from Dedicated Hosts, which reserve whole physical servers; dedicated-tenancy instances share host hardware allocated just to your account.

How to cut it

  • Check VPC and instance tenancy settings — switch to "default" unless dedicated hardware is a genuine compliance requirement.
  • If isolation is required, compare cost against a Dedicated Host, which can be cheaper at higher instance density and supports bring-your-own-license.
  • Apply commitment discounts compatible with dedicated tenancy to cut the per-instance premium.
Source: AWS docs →
Fargate-vCPU-Hours:perCPUAWS Fargate

Fargate vCPU and memory hours

The vCPU-hours and the companion memory GB-hours requested by your container tasks, billed per second from task start to stop — metered by resource request, not by underlying node.

Two independent meters (vCPU and memory) mean a task can be cheap on one dimension and expensive on the other; requesting more memory "just in case" inflates the memory line even when actual CPU use stays low.

Spikes when task count scales out, task definitions over-request vCPU/memory relative to real use, or tasks run longer than expected — a stuck shutdown hook keeps billable seconds ticking.

How to cut it

  • Right-size task definitions' CPU/memory requests against actual utilization instead of default templates.
  • Use a discounted interruption-tolerant capacity option for batch/async workloads.
  • Tighten auto-scaling scale-in thresholds so idle capacity doesn't linger.
  • Check for tasks stuck in a long-running drain/shutdown state that keep accruing billed seconds.
Source: AWS docs →
AmazonEKS-Hours:perClusterAmazon EKS

EKS cluster control-plane fee

A flat hourly fee charged per EKS cluster for the managed Kubernetes control plane, independent of how many nodes or pods run underneath it.

Multiplies quietly when teams spin up many small clusters — per-environment, per-team, or per-feature-branch — instead of sharing namespaces on fewer clusters; each cluster bills this fee around the clock even while completely idle.

Jumps sharply under a separate extended-support usage type if a cluster's Kubernetes version ages past the standard-support window and isn't upgraded.

How to cut it

  • Consolidate short-lived or low-traffic environments onto shared clusters with namespace isolation instead of one cluster per team or branch.
  • Automate teardown for ephemeral/preview clusters instead of letting them idle.
  • Stay current on Kubernetes version upgrades to avoid the extended-support surcharge.
Source: AWS docs →
Lambda-GB-SecondAWS Lambda

Lambda compute duration (GB-seconds)

The memory-allocated × duration charge for Lambda execution, metered in GB-seconds from invocation (including cold start) to return; the x86 line and the separate, cheaper Graviton/ARM line (Lambda-GB-Second-ARM) tier and bill independently.

Confusing because the number isn't invocation count or wall-clock time alone — doubling a function's memory setting doubles its GB-second rate even if duration is unchanged, so bumping memory to speed up a function can raise this line even with flat invocation counts.

x86 and ARM usage tier and bill completely independently, so migrating half your functions to arm64 doesn't just capture the per-GB-second discount — it also restarts that workload's progress toward Lambda's monthly volume pricing tiers on the x86 side.

How to cut it

  • Migrate eligible functions to arm64 (Graviton) for the automatic lower GB-second rate.
  • Tune memory allocation with a power-tuning tool rather than guessing — more memory can speed up CPU-bound code but isn't free.
  • Trim cold-start-heavy dependencies and package size, since init time before the handler returns is billed too.
  • Set tight function timeouts so a hung invocation doesn't run — and bill — far longer than intended.
Source: AWS docs →

Storage

EBS volumes and snapshots, S3's storage classes and request tiers, and the early-delete penalty nobody reads the fine print on.

EBS:VolumeUsage.gp2Amazon EBS

EBS General Purpose SSD storage (gp2/gp3)

Billing for the provisioned capacity (GB-month) of General Purpose SSD EBS volumes — gp2 or its newer, usually cheaper sibling gp3.

Every attached — and every unattached, un-deleted — gp2/gp3 volume bills continuously by provisioned size, not by data actually used, so oversized volumes or orphaned volumes left behind by terminated instances keep charging quietly.

gp2 is being phased out in favor of gp3, which is typically priced lower per GB and decouples performance from capacity, so heavy gp2 usage here usually flags an easy migration win.

How to cut it

  • Right-size volumes against actual usage instead of provisioning "just in case."
  • Migrate gp2 volumes to gp3 for the per-GB savings.
  • Find and delete unattached volumes left behind by terminated instances.
  • Automate snapshot-and-delete for stale dev/test volumes instead of doing it manually.
Source: AWS docs →
EBS:VolumeP-IOPS.piopsAmazon EBS

EBS Provisioned IOPS charge (io1/io2)

A separate per-IOPS-month charge for the performance you provisioned on io1/io2 volumes, billed apart from the volume's GB-month storage charge.

io1/io2 volumes bill storage and performance separately — capacity on one line, provisioned IOPS on this one — so teams provisioning IOPS "for headroom" often don't realize it's billed continuously whether or not that performance is ever used.

Because it's a distinct line item from storage, it can spike independently of any storage growth — a temporary IOPS bump for a migration or load test that never gets scaled back down.

How to cut it

  • Compare actual read/write operations against provisioned IOPS and right-size down.
  • Migrate io1 to gp3, which bundles a meaningful IOPS baseline into the base price with no separate per-IOPS charge below that.
  • Reserve the highest-IOPS tiers only for workloads that truly need that ceiling or durability.
  • Audit for volumes with elevated provisioned IOPS left over from one-off performance testing.
Source: AWS docs →
EBS:SnapshotUsageAmazon EBS

EBS snapshot storage

GB-month charge for EBS snapshots in the Standard tier, billed incrementally on the changed blocks each snapshot stores.

Automated backup schedules can accumulate hundreds of snapshots with no expiration, and because snapshots are incremental, each one keeps referencing changed blocks indefinitely until deleted.

The console's per-snapshot size figure overstates what deleting any single snapshot would actually free, since it's shared incremental data — teams often mis-estimate cleanup savings as a result.

How to cut it

  • Set retention/lifecycle policies to auto-expire old snapshots instead of letting them accumulate.
  • Delete snapshots for volumes or instances that no longer exist.
  • Consolidate redundant snapshots generated by CI/test pipelines that rebake images frequently.
  • Move long-retained, rarely-restored snapshots to a lower-cost archive tier.
Source: AWS docs →
TimedStorage-ByteHrsAmazon S3

S3 Standard storage

The core "you store data, you pay for it" charge — GB-months of object data and metadata held in S3 Standard storage, billed hourly and averaged over the month.

It's usually the single largest line on an S3 bill and grows silently: versioning-enabled buckets keep every prior object version, and incomplete multipart uploads consume storage without showing up in a normal object listing.

Because usage is measured in byte-hours but invoiced in GB-months, steady daily upload growth compounds across a billing cycle in a way that's easy to underestimate from a quick console glance. Note: this exact usage-type string is reused by several other AWS services too (DynamoDB and CloudWatch Logs among them) — the Service column, not the code alone, tells you which one you're looking at.

How to cut it

  • Enable lifecycle rules to expire noncurrent object versions and abort incomplete multipart uploads.
  • Use storage analytics to find cold data worth moving to a cheaper storage class.
  • Audit versioning-enabled buckets for unbounded historical version growth.
  • Compress or dedupe frequently-repeated large objects (logs, build artifacts) before they land in the bucket.
Source: AWS docs →
TimedStorage-SIA-ByteHrsAmazon S3

S3 Standard-Infrequent Access storage

GB-month storage charge for objects held in the S3 Standard-IA class — cheaper per-GB than Standard, but with per-GB retrieval fees and a 30-day minimum storage duration per object.

Lifecycle rules that auto-transition objects to IA to save money can backfire if the workload actually re-reads that data often — retrieval fees plus the minimum-duration penalty can make it more expensive than leaving it in Standard.

Small objects are a hidden trap: anything under roughly 128 KB is billed as if it were that minimum size, so transitioning many small files to IA can increase, not reduce, total storage cost.

How to cut it

  • Only transition objects with genuinely infrequent access, confirmed via storage-class analytics first.
  • Avoid transitioning small objects to IA — the minimum billable size erases the savings.
  • Make sure objects will live past the 30-day minimum before transitioning, or accept the early-delete charge as a known cost.
  • Consider an automatic tiering class instead of manual IA lifecycle rules when access patterns are unpredictable.
Source: AWS docs →
TimedStorage-GlacierByteHrsAmazon S3

S3 Glacier Flexible Retrieval storage

GB-month storage charge for archived objects held in the S3 Glacier Flexible Retrieval class, AWS's low-cost long-term archive tier.

Glacier's low per-GB rate is the headline, but it carries a 90-day minimum storage commitment and separate per-GB retrieval fees (priced very differently by speed tier) that show up on other bill lines, not this one.

Lifecycle policies that archive data too aggressively — logs a job still queries monthly, say — turn an intended storage saving into a net cost increase once retrieval and early-delete charges are added back in.

How to cut it

  • Archive only data confirmed cold via access logs or storage-class analytics before writing the lifecycle rule.
  • Use the slowest acceptable retrieval speed whenever the restore isn't time-critical; the price gap between tiers is large.
  • Ensure archived objects will sit at least 90 days to avoid the early-deletion charge.
  • For rarely-touched, longer-horizon data, compare against Deep Archive's lower rate (with a longer minimum and retrieval time).
Source: AWS docs →
Requests-Tier1Amazon S3

S3 request charges (PUT/COPY/POST/LIST and GET)

Per-request API charges — Tier1 covers PUT, COPY, POST, and LIST calls; a separate Tier2 line covers GET and most other read requests — billed per thousand requests.

The GET-request tier in particular blindsides teams: high-traffic static sites, CDN cache misses falling through to S3, or an application re-fetching objects in a loop can generate tens of millions of GET requests a month for what looks like a small bucket.

The write-request tier usually spikes from write-heavy patterns — one PUT per event or log line instead of batching — which multiplies request costs even while total bytes stored stay small.

How to cut it

  • Front S3 with a CDN and tune cache TTLs to cut repeated GETs at the origin.
  • Batch small writes into fewer, larger objects instead of one PUT per record.
  • Investigate and fix runaway polling, retry loops, or misconfigured sync jobs generating excess LIST/GET calls.
  • Use an inventory report instead of repeated LIST calls to audit bucket contents.
Source: AWS docs →
EarlyDelete-ByteHrsAmazon S3

S3 Glacier early-deletion charge

A prorated penalty charged when an object archived to S3 Glacier Flexible Retrieval is deleted, overwritten, or transitioned before its 90-day minimum storage commitment ends (parallel early-delete charges exist for the Instant Retrieval and Deep Archive classes).

One of the least-expected line items on an S3 bill: a lifecycle rule that archives to Glacier and a shorter-than-90-day expiration or re-transition rule layered on top will trigger this automatically, with no separate confirmation step.

The charge is calculated against the Glacier storage rate for the remaining days of the commitment, so it can effectively bill close to the full commitment period even though the object only sat there briefly — turning an intended archive-to-save move into a net loss.

How to cut it

  • Align lifecycle/expiration policies so objects won't be deleted or re-transitioned before the class's minimum duration (90 days for Glacier Flexible/Instant Retrieval, 180 for Deep Archive).
  • Don't archive data you expect to delete or reprocess within the next few months.
  • Audit lifecycle rule chains for conflicts, such as an expiration rule shorter than a transition rule's storage-class minimum.
  • Run storage-class analytics before enabling archive transitions to confirm the data's real deletion/access horizon.
Source: AWS docs →

Databases

RDS, Aurora, DynamoDB, and ElastiCache — instance hours, storage I/O, and the Multi-AZ charge that quietly doubles a bill.

InstanceUsage:db.m5.largeAmazon RDS

RDS instance hours

The hourly on-demand compute charge for a single-AZ RDS database instance of a given class, billed from launch until the instance is stopped or deleted.

This is the baseline line item for every running RDS instance, so it scales directly with instance class, count, and uptime — dev/test databases left running around the clock are a frequent source of avoidable spend.

It appears once per distinct instance class in use, so fleets with many one-off instance sizes produce many separate lines instead of one consolidated charge.

How to cut it

  • Stop or delete non-production instances outside business hours instead of leaving them running continuously.
  • Right-size the instance class using CPU/memory utilization metrics before assuming a bigger class is needed.
  • Buy Reserved Instances or a database savings plan for steady-state production instances.
  • Consolidate one-off instance classes onto a smaller set of standard sizes to simplify and reduce spend.
Source: AWS docs →
Multi-AZUsage:db.m5.largeAmazon RDS

RDS Multi-AZ instance hours

The hourly compute charge for a Multi-AZ RDS deployment, which bills for both the primary instance and its synchronous standby replica in another Availability Zone.

AWS's own documentation notes Multi-AZ deployments can cost roughly twice as much as single-AZ, because you're billed for two full instances (plus duplicated storage) instead of one — which routinely surprises teams who enabled it for durability without budgeting for the doubling.

It shows up as a separate usage type from plain instance hours, so cost reports that group only by instance type can hide it under an unexpected bucket unless grouped by usage type instead.

How to cut it

  • Confirm Multi-AZ is actually required for each database's durability/availability target before enabling it.
  • Use Multi-AZ only for production; keep dev/staging/QA databases single-AZ.
  • Apply commitment discounts — Multi-AZ standby instances qualify for the same discounts as primaries.
  • Consider a distributed-storage engine (no separate standby-instance charge) as a lower-cost HA alternative for some workloads.
Source: AWS docs →
RDS:GP3-StorageAmazon RDS

RDS gp3 storage

The per-GB-month charge for General Purpose SSD (gp3) storage provisioned on a single-AZ RDS instance, separate from the instance-hour and IOPS/throughput charges.

This line scales with allocated storage size, not actual data used — over-provisioned volumes (sized for future growth that never materialized) keep billing at the full allocated capacity every month.

gp3 storage includes a free baseline of IOPS and throughput, but exceeding that baseline generates separate line items, which is a common source of confusion when a storage bill jumps without a size change.

How to cut it

  • Right-size allocated storage to actual usage plus headroom, rather than over-provisioning up front.
  • Enable storage autoscaling instead of manually pre-allocating a large volume.
  • Check whether provisioned IOPS/throughput above the gp3 baseline are actually needed before paying for extra performance.
  • Periodically audit old snapshots and unattached storage tied to decommissioned instances.
Source: AWS docs →
RDS:ChargedBackupUsageAmazon RDS

RDS backup storage overage

The per-GB-month charge for RDS automated backups and manual snapshots once their combined size exceeds the free allotment (up to 100% of total provisioned database storage).

AWS gives free backup storage up to the sum of your database instances' allocated storage; once retained automated backups plus manual snapshots exceed that free tier, every extra GB is billed, which can appear suddenly after a retention window or snapshot count grows.

This charge can be broken out per DB instance in a Cost and Usage Report, rather than showing as one lump regional charge — useful for finding which specific database is driving it.

How to cut it

  • Shorten the automated backup retention period where compliance allows.
  • Delete stale manual snapshots that are no longer needed for recovery or compliance.
  • Export long-term-retention snapshots to cheaper cold storage instead of keeping them as database snapshots.
  • Tag DB instances so backup costs can be attributed per instance/team in Cost Explorer.
Source: AWS docs →
Aurora:ServerlessV2UsageAmazon Aurora

Aurora Serverless v2 ACU usage

The per-second (billed hourly) charge for Aurora Capacity Units (ACUs) consumed by an Aurora Serverless v2 instance, where each ACU is roughly 2 GiB of memory plus corresponding CPU and networking.

Serverless v2 autoscales capacity to match load, so a workload with sustained traffic, a query that pins CPU/memory, or a minimum-ACU floor set too high will keep ACU consumption — and this line item — elevated even when the app looks idle.

Because scaling happens continuously and is billed per second, spiky or noisy-neighbor query patterns can drive ACU usage up well beyond what average utilization graphs suggest, making this charge harder to predict than a fixed instance-hour price.

How to cut it

  • Lower the minimum ACU floor if it's set higher than the workload's true idle baseline.
  • Investigate and tune expensive queries that force scale-ups — missing indexes, full scans.
  • Correlate scaling events with specific traffic patterns using database performance metrics.
  • Compare against a provisioned Aurora instance if the workload's variability turns out to be low.
Source: AWS docs →
Aurora:StorageIOUsageAmazon Aurora

Aurora I/O requests

The per-operation charge for read and write I/O requests against Aurora's distributed storage layer, under the default storage configuration.

Every database page read that isn't served from the buffer cache, and every write, counts as a billed I/O operation — write-heavy workloads, cold caches after a failover or restart, or queries doing large scans generate outsized I/O charges relative to their compute footprint.

This is the exact line item Aurora's I/O-Optimized storage configuration is designed to eliminate: switching configurations removes all per-I/O charges in exchange for a higher storage-GB rate, which can meaningfully cut total Aurora cost once I/O is a large share of Aurora spend.

How to cut it

  • Check what share of total Aurora spend this line represents; a large share favors switching to the I/O-Optimized configuration.
  • Increase buffer pool cache hit ratio by right-sizing instance memory or tuning working-set size.
  • Reduce unnecessary full table scans and optimize indexes to cut read I/O.
  • Batch writes where possible to reduce the number of billed write operations.
Source: AWS docs →
WriteCapacityUnit-HrsAmazon DynamoDB

DynamoDB provisioned write capacity

The hourly charge for provisioned write capacity units reserved on a DynamoDB table, billed whether or not the capacity is actually consumed.

In provisioned capacity mode you pay for the capacity you configure, not what you use — throughput provisioned for a peak load that rarely materializes bills continuously at the reserved rate, which is the classic provisioned-vs-on-demand DynamoDB cost trap.

Auto scaling can mask this: if scaling policies are set too aggressively or the target utilization is too low, the table holds far more provisioned capacity than the steady-state workload needs.

How to cut it

  • Switch spiky or unpredictable tables to on-demand capacity mode and compare actual cost.
  • Tune auto-scaling target utilization closer to real usage instead of leaving conservative defaults.
  • Right-size manually-provisioned tables using consumed-capacity metric history.
  • Evaluate a lower-cost table class for write-light, storage-heavy tables to shift the cost balance.
Source: AWS docs →
NodeUsage:cache.m5.largeAmazon ElastiCache

ElastiCache node hours

The hourly on-demand charge per provisioned ElastiCache node of a given instance class, billed from launch until the node is terminated (partial hours round up to a full hour).

Every node in a cluster — including read replicas and all shards — bills separately, so scaling out shard or replica count directly multiplies this line item.

Nodes billed in an available or modifying state keep accruing charges even during low-traffic periods, since fixed-node ElastiCache doesn't scale compute down automatically the way a serverless option does.

How to cut it

  • Right-size node instance class using CPU/memory/eviction metrics rather than leaving default sizing.
  • Reduce replica or shard count for clusters that don't need the current level of read scaling or HA.
  • Buy Reserved Nodes for steady, predictable-size production caches.
  • Consider a serverless caching option for spiky or low/variable-traffic caches instead of fixed provisioned nodes.
Source: AWS docs →

Observability & management

CloudWatch, Config, and CloudTrail — the tools you turned on to control cost that can themselves become a line item.

DataProcessing-BytesAmazonCloudWatch

CloudWatch Logs ingestion

Charges for every byte of log data your applications, agents, or functions push into CloudWatch Logs.

Verbose application logging, debug-level log levels left on in production, or an agent shipping full request/response bodies inflates this line fast — it is metered per GB with no built-in cap, so one noisy service can dominate the entire CloudWatch bill.

Because it bills under the generic CloudWatch service line, teams often don't realize a single log group is responsible until they group Cost Explorer by both usage type and resource.

How to cut it

  • Raise log levels in production and strip high-cardinality/debug fields before they hit stdout.
  • Route noisy log groups through metric or subscription filters instead of ingesting everything at the standard rate.
  • Move logs you rarely query to a cheaper, infrequent-access log class.
  • Filter or sample at the source so only meaningful events are shipped at all.

$0.50 per GB ingested (Standard log class) — us-east-1, as of 2026-07

Source: AWS docs →
VendedLog-BytesAmazonCloudWatch

CloudWatch vended logs

The per-GB charge for logs that other AWS services generate and deliver into CloudWatch Logs on your behalf — VPC flow logs, DNS query logs, CDN logs, WAF logs — billed separately from logs your own code writes.

VPC flow logs in particular can generate enormous, continuous volume once enabled across every network interface in a busy VPC, and it's common to turn them on for a single investigation and forget to turn them back off.

Vended logs are priced and tracked separately from custom application logs, so a spike here points specifically at an AWS-managed logging feature rather than your own application code.

How to cut it

  • Scope flow logs to specific interfaces, subnets, or traffic types instead of an entire VPC.
  • Turn flow logs off once a troubleshooting window ends rather than leaving them running indefinitely.
  • Send high-volume vended logs to cheaper storage instead of CloudWatch Logs if you only need them for audit/compliance, not live queries.
  • Use an infrequent-access log class for vended logs you rarely query interactively.
Source: AWS docs →
CW:MetricMonitorUsageAmazonCloudWatch

CloudWatch custom metrics

The per-metric-per-month charge for every unique custom metric (and dimension combination) published to CloudWatch, whether from your own application, embedded metric format logs, or detailed instance monitoring.

Custom metrics are billed per unique dimension combination, not per metric name, so tagging a metric with a high-cardinality dimension (a request ID, a user ID, a container ID) can quietly generate thousands of billable metric series from what looks like a single metric.

Detailed monitoring and the CloudWatch embedded metric format both bill through this same usage type, so a spike can come from infrastructure nobody thought of as "custom metrics" at all.

How to cut it

  • Audit namespaces for unused or experimental metrics and delete the ones no dashboard or alarm references anymore.
  • Avoid high-cardinality dimensions on custom metrics; aggregate before publishing.
  • Only enable higher-resolution monitoring where it genuinely matters — basic monitoring is free.
  • Batch metric-publishing calls and review agent configs for metrics nobody ever looks at.

$0.30 per metric per month (first 10,000 custom metrics) — us-east-1, as of 2026-07

Source: AWS docs →
CW:AlarmMonitorUsageAmazonCloudWatch

CloudWatch alarms

The per-alarm hourly charge (prorated to per-month) for every standard-resolution metric alarm that exists in your account, whether or not it has ever fired.

Alarms created by infrastructure-as-code stacks or auto-scaling configurations often outlive the resources they monitor, sitting in an insufficient-data state and billing indefinitely until someone notices and deletes them.

Alarms built on metric-math expressions or anomaly-detection bands are charged per underlying metric referenced, not per alarm, so one alarm in the console can quietly bill as several.

How to cut it

  • Periodically find alarms stuck in an insufficient-data state tied to deleted resources.
  • Delete unused alarms left behind by decommissioned stacks or one-off experiments.
  • Avoid composite and high-resolution alarms unless the faster evaluation cadence genuinely changes response time.
  • Aggregate data upstream instead of building one metric-math alarm that references many individual metrics.
Source: AWS docs →
CW:RequestsAmazonCloudWatch

CloudWatch API requests

The per-1,000-request charge for CloudWatch API calls beyond the free tier — most visibly reads of metric data — billed once you exceed the free allotment.

Third-party dashboards and monitoring tools that poll CloudWatch on a schedule across every region in your account generate a steady stream of metric-read calls — the exact irony that a tool bought to give you visibility can itself become a line item on the bill.

AWS's own documentation calls this out directly: frequent programmatic reads of metric data can noticeably increase cost, and third-party monitoring tools often drive it by pulling data on a tight schedule to generate their own dashboards.

How to cut it

  • Restrict third-party integrations to the regions and namespaces you actually monitor instead of default "all regions" polling.
  • Switch high-frequency integrations from metric polling to a metric-streaming approach that pushes data instead of being polled.
  • Batch metric-publishing calls instead of one call per metric.
  • Identify exactly which caller or principal is generating the request volume before optimizing.
Source: AWS docs →
ConfigurationItemRecordedAWS Config

AWS Config configuration item recording

The per-item charge AWS Config bills every time it detects and records a change to a tracked resource's configuration — metered by how often your infrastructure actually changes, not a flat monthly fee.

Ephemeral or auto-scaled infrastructure can each generate several configuration items per launch — the resource itself, plus the network interfaces, groups, and attachments it creates — so a workload that churns instances hourly can dwarf its own compute cost in Config charges alone.

Because billing tracks activity rather than resource count or uptime, a resource stuck in a create/delete loop can spike this line from a few dollars to hundreds within a billing period with no corresponding change in what you're actually running.

How to cut it

  • Exclude high-churn, low-value resource types from the configuration recorder's recording scope.
  • Run ephemeral or bursty workloads in an account or organizational unit where this recording is disabled or scoped down.
  • Investigate any resource stuck in a create/delete loop — it's a common root cause of runaway configuration-item volume.
  • Review rule evaluations and conformance packs alongside configuration items, since both are billed by activity too.
Source: AWS docs →
PaidEventsRecordedAWS CloudTrail

CloudTrail data events

A per-100,000-events charge for CloudTrail data events — fine-grained, resource-level API activity such as object reads or function invocations — once data-event logging is turned on for a trail; management events are logged free by default.

Data events log every individual object- or resource-level API call, not just control-plane changes, so turning them on for a high-traffic bucket or a busy function can generate an enormous, continuously billed event volume compared to the free management-events tier.

The charge multiplies further with multi-region or organization-wide trails that replicate the same data-event logging across every account and region in scope, and can duplicate other access logging already delivering the same information.

How to cut it

  • Scope data-event logging to only the specific resources that actually need object-level audit trails, not "all resources of this type."
  • Use advanced event selectors to log only qualifying operations instead of every read/write.
  • Avoid duplicating access logging across multiple mechanisms for the same resource.
  • Review organization/multi-region trail scope periodically — logging every account and region by default multiplies cost beyond most audit requirements.
Source: AWS docs →

Security & keys

KMS, Secrets Manager, and GuardDuty — small per-unit charges that add up fast at scale.

KMS-KeysAWS Key Management Service

KMS customer-managed key, monthly fee

A flat monthly charge (prorated hourly) for every customer-managed key you've created in KMS, whether or not it's ever used to encrypt anything.

This is the largest line item for teams that create a lot of keys — one per bucket, one per table, one per environment per service — instead of reusing a small number of keys across resources.

It also spikes when automatic or on-demand key rotation happens: the first rotations of a key's material in a month can each add another prorated monthly charge.

How to cut it

  • Consolidate: use one key per service or data-classification tier rather than per resource — access policies, not key count, should enforce isolation.
  • Delete unused keys with no recent decrypt/encrypt activity.
  • Avoid enabling automatic rotation on keys that don't need it, and don't trigger repeated on-demand rotations within the same billing month.
  • Group by usage type and API operation in Cost Explorer to separate current-key vs. rotated-key charges.
Source: AWS docs →
KMS-RequestsAWS Key Management Service

KMS API request charge beyond the free tier

Billing for KMS API calls (encrypt, decrypt, generate-data-key, and similar) once you exceed the monthly free-tier request allotment.

Workloads that read or write large numbers of individual objects or items with server-side encryption enabled can generate an enormous number of per-object KMS calls, since each object read/write can trigger its own key-generation or decrypt call.

Because the per-request price is tiny, this charge is easy to dismiss until request volume reaches millions per month — at which point it becomes one of the largest and least-expected line items on the bill.

How to cut it

  • Turn on bucket-level key reuse for server-side encryption — this can cut request volume dramatically by reusing a bucket-level data key instead of calling KMS per object.
  • Cache data keys client-side where the SDK/library supports envelope-encryption caching, instead of calling the API per operation.
  • Use detailed billing data to identify which caller, service, or key is generating the request volume before optimizing.
  • Batch or reduce per-object encryption operations where the access pattern allows it.
Source: AWS docs →
AWSSecretsManager-SecretsAWS Secrets Manager

Secrets Manager per-secret storage fee

A flat monthly charge (prorated hourly) for every secret stored in Secrets Manager, including each cross-region replica, regardless of how often it's used.

This is a storage cost, not a usage cost, so it accumulates purely from secret count — it's the dominant Secrets Manager charge for most accounts, not the API calls.

It commonly balloons from secret sprawl: the same credential duplicated per environment, per region, and per microservice, or old/rotated secrets that were never cleaned up.

How to cut it

  • Audit for duplicate or unused secrets and delete (or schedule-delete) ones with no recent access activity.
  • Consolidate secrets that don't need per-service isolation, and reconsider whether every region needs its own replica.
  • Use cost allocation tags on secrets to attribute per-secret storage cost to the owning team/app, which makes sprawl visible.
  • For low-sensitivity, non-rotating config values, consider a free parameter store instead of Secrets Manager.
Source: AWS docs →
AWSSecretsManagerAPIRequestAWS Secrets Manager

Secrets Manager API request charge

Billing for API calls to Secrets Manager — retrieving, describing, writing, and listing secrets — at a small per-10,000-requests rate; every operation counts, not just retrievals.

This spikes when application code fetches a secret on every invocation instead of caching it — a function calling the retrieval API on every cold and warm invocation, or a container re-reading a secret on every request rather than once at startup.

High-frequency polling patterns (health checks, config-refresh loops) can also drive this up even though no secret value actually changed.

How to cut it

  • Cache secret values client-side (in memory, or via a caching library) so repeated calls don't hit the API each time.
  • Fetch secrets once per process/container lifecycle rather than per invocation.
  • Reduce polling frequency for rotation-check or config-refresh loops; react to rotation events instead of repeatedly polling.
  • Group by usage type and API operation to find which call type and caller is driving volume.
Source: AWS docs →
PaidEventsAnalyzed-BytesAmazon GuardDuty

GuardDuty log analysis, per GB

GuardDuty's charge for the volume (in GB) of network flow and DNS query log data it analyzes each month, billed on a tiered per-GB schedule after any free-trial allowance.

This scales directly with network traffic volume, so it grows with egress/ingress and DNS query volume — busy NAT gateways, chatty microservices, or a sudden traffic spike all drive more log data into GuardDuty for analysis.

New accounts or newly-enabled detectors get a free trial period, so the charge can appear to jump sharply once that trial ends even though traffic hasn't changed.

How to cut it

  • Use GuardDuty's own usage statistics to identify which accounts or regions are contributing the most analyzed bytes.
  • Reduce unnecessary network chatter feeding the underlying logs — tighten security groups, reduce noisy health-check or discovery traffic — rather than disabling the logs themselves.
  • Take advantage of the built-in volume-tiered discount; consolidating accounts into an organization-wide setup can shift usage into cheaper tiers.
  • Don't disable GuardDuty to save cost; instead confirm it's only enabled where needed, not duplicated across redundant member accounts.
Source: AWS docs →

AI & ML

Bedrock tokens and SageMaker instance-hours — plus the AI spend that never touches an AWS bill at all.

USE1-Claude4.6Sonnet-input-tokensAmazon Bedrock

Bedrock input tokens (per model)

Every token sent into a Bedrock model as part of the prompt — system instructions, chat history, retrieved context, few-shot examples — is metered and billed separately per model, distinct from output tokens.

Input-token spend climbs fastest when prompts carry more context than the task needs: long system prompts, unpruned chat history, or retrieval that stuffs in whole documents instead of relevant chunks.

Because the usage type is per-model, a silent model switch or an A/B test can quietly double the number of these line items without the aggregate number appearing to move.

How to cut it

  • Trim system prompts and cap retrieved context to what's actually relevant.
  • Truncate or summarize conversation history instead of resending the full transcript each turn.
  • Route repeated static context through prompt caching so it bills as a cache read, not full input.
  • Use a smaller, cheaper model for steps that don't need frontier-level reasoning.
Source: AWS docs →
USE1-Claude4.6Sonnet-output-tokensAmazon Bedrock

Bedrock output tokens (per model)

Tokens the model generates in its response are billed as a separate line item from input tokens, usually at a materially higher per-token rate.

Output cost spikes with verbose responses, reasoning-style generation, or a maximum-output ceiling set far higher than the task needs, which lets occasional runaway completions run up the bill.

Retried requests — timeouts, malformed output, agent loops — each generate a full new completion, so a flaky integration can multiply output-token cost without any increase in genuinely useful responses.

How to cut it

  • Set explicit, tight output-length limits per use case instead of a generous default.
  • Prompt for concise, structured output rather than free-form prose.
  • Turn off extended reasoning modes for tasks that don't need them.
  • Cache and reuse completions for repeated or templated queries.
Source: AWS docs →
USE1-Claude4.6Sonnet-cache-read-input-token-countAmazon Bedrock

Bedrock prompt-cache read tokens

Tokens served from Bedrock's prompt cache — instead of being reprocessed as full input — appear as their own usage type, billed at a steep discount versus a normal input token.

This line item shows up as soon as an application uses prompt caching on a supported model; teams who didn't know caching was enabled are often confused to see a brand-new, unfamiliar usage type appear on the bill even though it represents savings, not new spend.

The savings only materialize if the cache is actually being hit: for a bursty, low-repeat workload where cache-write volume dominates over cache-read, the cache overhead can cost more than it saves.

How to cut it

  • Check the cache read-to-write ratio before assuming caching is saving money.
  • Put static, reusable content (system prompt, shared context) first in the prompt so the cache prefix actually matches across calls.
  • Only enable caching for workloads with genuinely repeated prompt prefixes, not one-off requests.
Source: AWS docs →
USE1-Host:ml.g5.xlargeAmazon SageMaker

SageMaker real-time endpoint hours

Billed for every hour a SageMaker real-time inference endpoint's instance is running, regardless of whether it's actively serving prediction traffic.

GPU endpoints are among the most expensive per-hour instance types available, and they're commonly left running around the clock after a demo, proof of concept, or project winds down, because nothing prompts anyone to delete the endpoint.

Endpoints are also frequently over-provisioned — sized, or replicated across multiple instances, for peak load that only shows up occasionally, so most hours are billed at the full GPU rate for near-idle capacity.

How to cut it

  • Delete or stop endpoints as soon as a project or experiment is done.
  • Use serverless or asynchronous inference for spiky or low-traffic workloads instead of an always-on real-time endpoint.
  • Enable endpoint auto-scaling, including scale-to-zero where supported, so idle periods don't bill at full capacity.
  • Right-size the instance type/family to the model's actual latency and throughput needs.
Source: AWS docs →
USE1-Notebk:ml.g4dn.8xlargeAmazon SageMaker

SageMaker notebook instance hours

Billed for every hour a classic SageMaker notebook instance sits in an active state, independent of whether anyone is actively working in it.

Data scientists routinely start a notebook instance for a task and leave it running overnight, over a weekend, or indefinitely after the analysis is finished — there's no default timeout, so the meter keeps running.

Larger instance types, including GPU ones, get picked for a single heavy job and then never scaled back down for routine day-to-day notebook work.

How to cut it

  • Attach an auto-stop-idle lifecycle configuration so notebooks shut down automatically after a period of inactivity.
  • Schedule automatic start/stop around normal working hours.
  • Move to a pay-per-app compute model instead of always-on classic notebook instances.
  • Right-size the instance type to what the notebook workload actually needs day-to-day.
Source: AWS docs →

AI spend that never touches an AWS bill is easy to miss entirely: a direct Anthropic API subscription, an OpenAI API key billed straight to a corporate card, or a third-party AI vendor invoice shows up nowhere in Cost Explorer or a Cost and Usage Report, no matter how closely you watch every line item above. A team can be disciplined about every Bedrock token and still get blindsided by spend building up entirely outside AWS — which is exactly why AI cost visibility has to span every model provider a team actually uses, not just the one that happens to bill through the AWS account. See LLM API pricing, the AI agent cost guide, and AI/LLM cost monitoring.

FAQ

Common questions about reading an AWS bill

Where do I actually see AWS usage types on my bill?

In the AWS Cost Explorer console, set "Group by" to Usage type instead of just Service — that's the exact field this page decodes. For row-by-row detail beyond what Cost Explorer's UI shows, turn on a Cost and Usage Report (CUR) and look at the lineItem/UsageType column; it's the identical string.

Why does the same usage type show up with a different prefix in different accounts?

Usage types are region-scoped: a code with no region prefix generally represents us-east-1 for the classic data-transfer family, while every other region gets its short code (USE2, USW2, EUC1, APS1, and so on) prepended. Some services — Elastic Load Balancing, Transit Gateway, Public IPv4 — prefix us-east-1 explicitly too, so the "no prefix = us-east-1" rule isn't universal across every service.

What's the difference between a usage type and an operation?

Usage type is the billing meter — the dimension AWS actually charges you on, like NatGateway-Bytes or BoxUsage:m5.large. Operation (lineItem/Operation in a CUR) is the specific API call that triggered it, like RunInstances or GetObject. Several different operations can roll up into the same usage type, and the same usage type can be triggered by more than one operation, which is why filtering by usage type alone sometimes isn't specific enough to find the root cause.

Why is my NAT gateway bill so much higher than I expected?

A NAT gateway bills three separate ways: a flat hourly uptime charge, a per-GB data-processing charge for every byte that passes through it, and then whatever standard data-transfer charge that traffic would have incurred anyway. Traffic that could instead reach an AWS service through a VPC endpoint — which has no per-GB processing fee for gateway endpoints — is the most common avoidable driver.

Is data transfer into AWS free?

Generally yes: data transfer from the public internet into an AWS region, and the inbound leg of a transfer between two AWS regions, is priced at $0. Only the sending side — internet egress out of a region, or the outbound leg of an inter-region transfer — actually carries a charge. Cross-AZ (regional) transfer is the one common exception, billed on both the sending and receiving side.

Why did I get billed for a public IP address I'm not even using?

AWS began charging for every public IPv4 address on February 1, 2024 — not just "extra" or idle Elastic IPs, as before. An unattached Elastic IP left over from a decommissioned instance now bills at the same hourly rate as one that's actively serving traffic, so idle allocations are pure waste and worth releasing.

Does CostMon replace reading my AWS bill line by line?

That's the point of it. CostMon pulls these same usage-type-level records automatically, normalizes them alongside your other cloud and AI spend, and alerts you before a spike like an unattached Elastic IP or a runaway CloudWatch Logs group turns into a surprise on the invoice — so you don't have to reverse-engineer usage types by hand every month.

See what your stack really costs.

Connect your first providers in minutes and give finance and engineering one number they both trust. Flat pricing — never a percentage of your bill or your savings.

Esc