What CloudWatch Logs actually cost (2026)

Akal Cloud Updated 6 min read

Quick answer

Three meters: ingestion per GB, storage per GB-month for as long as retention keeps it, and Logs Insights per GB scanned. The Infrequent Access log class lowers ingestion only, since AWS states the classes differ in ingestion cost alone while storage and Insights charges are identical. It also removes metric filters, subscription filters, Live Tail and field indexing, so you cannot alarm on it. And a log group's class cannot be changed after creation.

CloudWatch Logs has two log classes, one is half the ingestion price, and the choice is permanent: AWS does not let you change a log group's class after it is created. The cheaper one also silently removes the features most teams built their alarms on.

What do CloudWatch Logs cost?

Three meters, and the one people budget for is not usually the one that grows. Ingestion is charged per GB as data arrives. Storage is charged per GB per month for as long as retention keeps it. Query is charged per GB scanned by Logs Insights.

MeterCharged onLever
IngestionGB arriving, by log classLog volume, and the class you chose
StorageGB retained per monthRetention setting
Logs Insights queryGB scanned per queryTime range and field indexing

Current per-GB rates are on the CloudWatch pricing page. Read them there. What is worth internalising instead is the structure, because the structure is what you can change.

One distinction to get right before comparing any numbers. Logs that AWS services deliver on your behalf are billed on a separate tiered meter called Vended Logs, described on that page as "logs from specific AWS services that are available at volume tiered pricing". VPC Flow Logs, and the tiering that applies to them, are covered in what VPC Flow Logs actually cost. This post is about the log groups your own applications write to.

What is the Infrequent Access log class?

A cheaper ingestion tier with features removed. The log classes documentation describes Infrequent Access as offering "a subset of CloudWatch Logs capabilities including managed ingestion, storage, cross-account log analytics, and encryption with a lower ingestion price per GB", and positions it as "ideal for ad-hoc querying and after-the-fact forensic analysis on infrequently accessed logs."

The pricing difference is narrower than it sounds, and AWS is precise about where it applies: "For charges, the Standard and Infrequent Access log classes differ in ingestion costs only. Storage charges and CloudWatch Logs Insights charges are the same in each log class."

So Infrequent Access reduces one of the three meters. If your bill is dominated by storage because retention is set to never expire, changing log class saves you nothing at all.

What do you give up in Infrequent Access?

Four features, and between them they cover most of what a log group is wired into. From the supported-features table:

FeatureStandardInfrequent Access
Managed ingestion and storageYesYes
Cross-account featuresYesYes
Encryption with AWS KMSYesYes
Logs Insights queriesYesYes, most commands
Export to Amazon S3YesYes
Metric filtersYesNo
Subscription filtersYesNo
Live TailYesNo
Field indexingYesNo

The first two are the ones that break things. No metric filters means you cannot turn a log line into a CloudWatch metric, which means you cannot alarm on the contents of an Infrequent Access log group. No subscription filters means you cannot stream it to Firehose, Lambda or OpenSearch either.

That combination rules Infrequent Access out for anything on an alerting path, and rules it in for exactly what AWS says: logs you keep in case somebody has to go looking. Debug logs, verbose access logs, per-request traces. The test is whether anything automated reads the log group. If nothing does, it is a candidate.

Can you change a log group's class later?

No, and this is the sentence to read twice: "After a log group is created, its log class can't be changed."

Which makes this a migration rather than a setting. To move a stream to Infrequent Access you create a new log group in that class, repoint whatever writes to it, and let the old group age out under its retention policy. On Lambda that is a function configuration change; on ECS or EKS it is a log driver or agent change. Budget for the work, and do it once per stream rather than discovering the constraint halfway through.

The corollary is that new log groups deserve a decision at creation time. Defaulting everything to Standard is the expensive habit, and defaulting everything to Infrequent Access breaks alarms you have not written yet.

Why is storage often the bigger number?

Because ingestion is charged once and storage is charged every month until retention deletes the data. And retention has no default expiry: AWS states "By default, log data is stored in CloudWatch Logs indefinitely. However, you can configure how long to store log data in a log group." A stream ingested two years ago into a log group nobody set retention on is still billing today.

Retention is the single highest-leverage setting in CloudWatch Logs and it is the one most often left unset. Find the groups with no expiry:

aws logs describe-log-groups \
  --query 'logGroups[?retentionInDays==`null`].[logGroupName,storedBytes,logGroupClass]' \
  --output table

Then sort by storedBytes and set retention on the largest ones first. A single command changes it, and the effect is immediate on the storage meter:

aws logs put-retention-policy \
  --log-group-name /aws/lambda/my-function \
  --retention-in-days 30

Where you genuinely need years of history, exporting to S3 and expiring the CloudWatch copy is usually cheaper than CloudWatch storage, and Export to S3 is available in both log classes. Check the object sizes before choosing a storage class though: log exports are small files, and the 128 KB minimum billable size on Standard-IA can make a cheaper class cost more.

What makes a Logs Insights query expensive?

Bytes scanned, which is a function of the time range rather than the result count. A query over 30 days scans 30 days of that log group whether it returns one row or a million, so narrowing the range is the whole optimisation. This is the same economics as Athena's per-query scan charge, without an equivalent hard cancel control.

AWS also publishes a dedicated guide to analyzing, optimizing and reducing CloudWatch costs, which is worth reading alongside the log group and retention reference.

Field indexing reduces scanned volume on Standard log groups, and it is one of the features Infrequent Access does not have. That is a real cost interaction: choosing the cheaper ingestion class removes the mechanism that makes querying cheaper. If a log group is both high volume and frequently queried, Standard with indexing can end up cheaper overall than Infrequent Access without it.

Can you attribute CloudWatch Logs cost to a team?

CloudWatch appears as its own service, and usage type separates ingestion from storage from queries:

aws ce get-cost-and-usage \
  --time-period Start=2026-07-01,End=2026-08-01 \
  --granularity MONTHLY \
  --metrics UnblendedCost UsageQuantity \
  --group-by Type=DIMENSION,Key=USAGE_TYPE \
  --filter '{"Dimensions":{"Key":"SERVICE","Values":["AmazonCloudWatch"]}}'

Per log group, that is as far as Cost Explorer goes. Log groups are not tagged resources in the cost data by default, so attributing spend to a team means either naming conventions you can group on or activating tags on the log groups themselves, which runs into the delays described in why cost allocation tags show up empty.

Worth knowing what is not covered anywhere in this data: CloudWatch is not in Cost Optimization Hub's supported resource list, so no AWS recommendation engine will tell you a log group has no retention policy. That check has to be yours, and the command above is the whole of it.

Share LinkedIn X Hacker News Reddit

See this on your own bill

Akal Cloud connects in about two minutes and shows the same numbers against your real AWS accounts.

Get started on AWS Marketplace

Related reading