Omni FinOps

Cloud bill spikes explained, for engineering teams facing unexpected AWS and Google Cloud charges

The usual causes of a sudden AWS cost increase or Google Cloud bill spike, how to trace unexpected cloud charges to a resource, and how to stop the next one.

Mateo VargasUpdated · 9 min read
Contents
  1. Read the shape of the cloud bill spike first
  2. The usual causes of an AWS cost increase
  3. Unexpected cloud charges on Google Cloud
  4. Trace the spike to a resource
  5. Check what changed that day
  6. Stop the next spike before the invoice
  7. How Omni FinOps handles a spike
  8. Frequently asked questions

In short

  • A cloud bill spike has a first day; daily cost shows whether it’s a one-off, a lasting step or a slow ramp.
  • When usage is flat but cost jumped, look for an expired commitment, ended credits, or a version in paid extended support.
  • Most spikes trace to compute that never scaled in, NAT data processing, log ingestion, data transfer or forgotten resources.

A cloud bill spike feels random when it lands, but it almost never is. Something started on a specific day, in a specific service, and usually on one resource someone launched, scaled or forgot. This post is for engineering teams on AWS and Google Cloud who just opened a bill bigger than last month’s: the usual causes of unexpected cloud charges, how to trace one to the resource behind it, and how to hear about the next one before the invoice does.

The order matters. Read the shape of the change first, then check the short list of usual suspects, then trace it down to a resource. Most spikes are found in under an hour that way.

Read the shape of the cloud bill spike first

A monthly total hides what happened. Switch to daily cost for the last 30 to 60 days and look at the shape of the change, because each shape points somewhere different.

Shape What it usually means Where to look first
One high day, then back to normal A one-off: a backfill, a load test, a large data transfer, a heavy query Data transfer and query services on that day
A step up that stays up New steady cost: something scaled out, a new service launched, or a discount ended Compute, the first day of the step
A slow ramp over weeks Something accumulating: logs, snapshots, storage, or traffic growing with usage Storage, logging and network usage types
A jump on the 1st of the month A monthly charge, or a commitment or credit that ended with the old month Commitments, credits and support fees

The first day of a step is the most useful fact you’ll find. It lines up with a deploy, a scaling event, a migration or a new team’s workload, and it tells you which day to compare against which.

The usual causes of an AWS cost increase

Most AWS cost increases come from a short list. Check these before anything exotic.

What you see Usual cause
EC2 instance hours up since one day An Auto Scaling group or Kubernetes node group scaled out and never scaled back in
EC2 - Other up, NatGateway-Bytes usage type More traffic through a NAT gateway, often to S3 or DynamoDB
CloudWatch up, log ingestion usage types Debug logging left on after an incident
VPC up, public IPv4 usage More public IPv4 addresses, each billed by the hour
EKS or RDS up with no new usage A Kubernetes or database version left standard support
Same usage, higher cost A Savings Plan or Reserved Instance expired, or credits ran out

A few of these deserve numbers. NAT gateways bill $0.045 per hour plus $0.045 per GB processed in US East as of October 2026 (VPC pricing). Traffic to S3 and DynamoDB doesn’t need to go through one: gateway endpoints for those two services have no additional charge (AWS docs). Every public IPv4 address costs $0.005 per hour, in use or idle (VPC pricing), so unused public IPs add up across many accounts. CloudWatch Logs bills $0.50 per GB ingested on the standard log class in US East after the free tier (CloudWatch pricing), so one chatty service at debug level can move the bill on its own.

Version support is the cause teams miss most. An EKS cluster costs $0.10 per hour on standard support and $0.60 per hour once its Kubernetes version enters extended support, 14 months after the version’s release in EKS (EKS pricing). RDS Extended Support starts charging the day after a major version’s end of standard support (RDS for MySQL pricing). Nobody launched anything, and the bill still went up.

The last row is the most confusing one. When a Savings Plan or Reserved Instance expires, the same instances keep running at on-demand rates. When startup or promotional credits run out, the bill doesn’t grow; it just stops being covered. In both cases usage is flat and cost jumps, which is your clue.

Unexpected cloud charges on Google Cloud

Google Cloud has its own versions of the same traps.

  • Cloud NAT. Public NAT bills $0.045 per GiB processed in every region, plus $0.0014 per hour for each VM using the gateway, up to 32 VMs (Cloud NAT pricing). Private Google Access lets VMs without external IPs reach Google APIs without going through NAT.
  • BigQuery on-demand queries. On-demand analysis costs $6.25 per TiB scanned after the first free TiB each month (BigQuery pricing). A dashboard refreshing a SELECT * over a large table every few minutes is a classic spike.
  • Cloud Logging. Log storage costs $0.50 per GiB after the first 50 GiB per project per month (Google Cloud Observability pricing). Exclusion filters on the log router stop noisy logs before they’re billed.
  • Autoscaling that stayed up. A managed instance group or a GKE node pool that scaled out for a peak and kept its new floor.
  • Discounts and credits ending. A committed use discount reached its end date, or trial or startup credits ran out. The $300 Free Trial credit, for example, lasts 90 days (Google Cloud docs).

Trace the spike to a resource

The method is the same on both clouds: find the first day, then narrow by service, then by meter, then by account or project, then by resource. Each step cuts the search space.

On AWS, Cost Explorer does the first steps: daily granularity, group by service, then filter to the service and group by usage type. The step-by-step AWS guide has the console path and every CLI query. The short version is one command, run for the day before and the first day of the spike:

aws ce get-cost-and-usage \
  --time-period Start=2026-10-10,End=2026-10-11 \
  --granularity DAILY \
  --metrics UnblendedCost \
  --group-by Type=DIMENSION,Key=SERVICE Type=DIMENSION,Key=USAGE_TYPE \
  --query 'ResultsByTime[].Groups[].[Keys[0], Keys[1], Metrics.UnblendedCost.Amount]' \
  --output text | sort -t$'\t' -k3 -rn | head -20

On Google Cloud, start in the Cloud Billing Reports page: group by service, then by SKU, and filter to the project that moved. To reach the resource, query the detailed usage cost export in BigQuery. It has a resource.name column for services that report resource-level usage, such as Compute Engine:

SELECT
  DATE(usage_start_time) AS day,
  service.description AS service,
  sku.description AS sku,
  project.id AS project,
  resource.name AS resource,
  ROUND(SUM(cost) + SUM(IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)), 2) AS net_cost
FROM `my-project.billing.gcp_billing_export_resource_v1_XXXXXX_XXXXXX_XXXXXX`
WHERE DATE(usage_start_time) BETWEEN '2026-10-09' AND '2026-10-10'
GROUP BY day, service, sku, project, resource
ORDER BY net_cost DESC
LIMIT 50;

Credits are negative amounts, so adding them gives the cost you actually pay. The query itself is billed like any other on-demand BigQuery query, by the bytes it scans.

Check what changed that day

Once you know the service and the day, ask what was created then, and by whom. On AWS, list instances launched on the first day of the spike, then ask CloudTrail who launched them. Both commands only read, and lookup-events covers the last 90 days of management events in the Region you query:

aws ec2 describe-instances \
  --filters Name=launch-time,Values='2026-10-10*' \
  --query 'Reservations[].Instances[].[InstanceId, InstanceType, LaunchTime]' \
  --output table

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=RunInstances \
  --start-time 2026-10-10 --end-time 2026-10-11 \
  --query 'Events[].[EventTime, Username]' --output table

On Google Cloud, list new VMs and read the Admin Activity audit log, which is always on:

gcloud compute instances list \
  --filter="creationTimestamp>='2026-10-10'" \
  --format="table(name, zone.basename(), machineType.basename(), creationTimestamp)"

gcloud logging read 'protoPayload.methodName:"compute.instances.insert"' \
  --freshness=3d --limit=20 \
  --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.resourceName)"

If nothing new was created, the cause is a rate, not a resource: an expired commitment, credits that ended, or a version that left standard support. Check those dates next.

Stop the next spike before the invoice

Finding a spike three weeks later costs three weeks of it. Four habits shrink that gap:

  1. Turn on anomaly detection. Both clouds offer it free and it flags spend that breaks its own pattern within about a day. The cloud cost anomaly detection guide covers the setup and thresholds.
  2. Set budgets with forecast alerts. A budget tells you the month is heading over before it is. See cloud budget alerts.
  3. Tag or label by owner. A spike nobody owns sits in the bill longest. A team tag turns “the bill is up” into a message to one person; cost allocation by team explains how.
  4. Keep a calendar of end dates. Savings Plans, Reserved Instances, committed use discounts, credits and Kubernetes version support all end on known days.

Clean up what got left behind, too. The scaled-out nodes that stayed and the volumes from terminated instances are the same idle and orphaned resources that make the next spike harder to read.

How Omni FinOps handles a spike

Omni FinOps reads daily cost from Cost Explorer on AWS and from the billing export in BigQuery on Google Cloud, through read-only access. It compares each day, per account and service, with the same weekday over the four weeks before, marks the first day spend broke that pattern, and names the regions and resources whose cost rose, in one sentence with the dollars above typical. Each anomaly moves through statuses with a comment for every change, and a spend anomaly email can go to up to 10 people. It never changes anything in your cloud.

Frequently asked questions

Why did my cloud bill spike when nothing changed?

Usually a rate changed, not your usage. A Savings Plan, Reserved Instance or committed use discount expired and the same resources went back to on-demand prices, credits ran out, or a Kubernetes or database version moved into paid extended support. Compare usage quantity with cost: if usage is flat and cost jumped, look at commitments, credits and support dates before looking for new resources.

How do I find what caused an AWS cost increase?

Switch Cost Explorer to daily granularity and find the first day of the increase. Group that day and the day before by service, then filter to the service that moved and group by usage type. The usage type names the meter, such as instance hours of one type or NAT gateway bytes. Then list resources created that day and check CloudTrail for who created them.

What are the most common unexpected cloud charges?

The usual ones are compute that scaled out and never scaled back in, NAT gateway data processing, data transfer between regions or to the internet, log ingestion left at debug level, public IPv4 addresses, paid extended support for old Kubernetes or database versions, and expired discounts. On Google Cloud, large on-demand BigQuery scans are another frequent cause.

How quickly can I see a cloud bill spike?

Not instantly. AWS cost data in Cost Explorer can lag by up to 24 hours, and AWS Cost Anomaly Detection can take up to 24 hours to flag an anomaly after the usage happens. Google Cloud billing data also arrives with a delay. Expect to hear about a spike the next day at best, which is why automatic alerts beat checking the bill at month end.

How do I stop a cloud bill spike from happening again?

Turn on the free anomaly detection in AWS and Google Cloud, set monthly budgets with forecast alerts, tag or label every resource with an owning team, and keep a calendar of when commitments, credits and version support end. Then fix the specific cause: scale-in rules for autoscaling, gateway endpoints for S3 traffic, log exclusions, or a version upgrade.

Does Omni FinOps change anything when it finds a spike?

No. Omni FinOps only reads cost, inventory and CPU metrics, through a read-only IAM role on AWS and read-only Google sign-in on Google Cloud. It explains the spike and names the resources behind it, and any fix it suggests comes with the exact command for your team to run with its own credentials.

Mateo Vargas writes Omni FinOps’ cost guides, from the same rules the product runs on every refresh. Prices and product facts are as of October 12, 2026; check each provider’s pricing page.

More from the blog