Home · About · Services · Industries · Projects · Products · Process · Blog · FAQ · Contact
How to reduce cloud costs without breaking production: a checklist The order we work in when cutting an AWS or Azure bill: find the spend, delete what nobody uses, rightsize, fix data transfer, then commit. With commands and…
The finance team forwards the monthly invoice with one line: why is this 30 percent higher than last year? Nobody launched anything big. The bill grew one forgotten volume, one oversized database and one chatty service at a time. Now someone has to bring it down, and the one thing they cannot do is take the application offline while trying.
The short answer: reduce cloud costs in a fixed order. First see where the money goes, then delete resources nobody uses, then rightsize what is left using real utilisation data, then fix data transfer and storage tiers, and only then buy Savings Plans or reservations for the steady baseline. Change one thing at a time, with a rollback ready.
The order matters. Buying a three-year commitment before rightsizing locks in waste. Deleting things before you know who owns them is how production breaks. Below is the sequence we follow on AWS and Azure accounts, with the checks we run between steps.
Step 1: see the bill by service, account and owner Start with read-only access. You cannot cut what you cannot attribute. Pull the last three months grouped by service, then by usage type within the top five services. On AWS, Cost Explorer does this in the console, or from the CLI:
aws ce get-cost-and-usage \
--time-period Start=2026-07-01,End=2026-10-01 \
--granularity MONTHLY \
--metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICEOn Azure, Cost Management cost analysis grouped by resource group and meter gives the same picture. In most accounts we look at, a handful of line items make up the bulk of the spend: compute, managed databases, storage, and data transfer or NAT. That is where the effort goes. A 50 percent saving on a line that costs very little is not worth a change window.
While you are here, set up tagging for owner, environment and application, and activate those tags as cost allocation tags on AWS. Untagged spend is the spend nobody defends, and it is often the easiest to remove.
Step 2: delete what nobody uses This is the safest saving because nothing depends on it, provided you confirm that first. The usual suspects:
Unattached block storage volumes left behind after instances were terminated. Old snapshots and machine images from migrations and one-off tests. Public IPv4 addresses that are allocated but idle. AWS charges for every public IPv4 address, attached or not, at $0.005 per hour. Load balancers with no healthy targets, and test environments that run around the clock. Log groups with retention set to never expire, which is the CloudWatch default. Incomplete multipart uploads sitting in S3 buckets, invisible in a normal listing but still billed. These commands list the obvious ones. They only read; they do not delete anything.
# AWS: volumes not attached to any instance
aws ec2 describe-volumes --filters Name=status,Values=available \
--query 'Volumes[].[VolumeId,Size,CreateTime]' --output table
# AWS: Elastic IPs not associated with anything
aws ec2 describe-addresses \
--query 'Addresses[?AssociationId==null].[PublicIp,AllocationId]' --output table
# AWS: your snapshots, oldest first
aws ec2 describe-snapshots --owner-ids self \
--query 'sort_by(Snapshots,&StartTime)[].[SnapshotId,VolumeSize,StartTime,Description]' --output table
# Azure: managed disks not attached to a VM
az disk list --query "[?diskState=='Unattached'].[name,resourceGroup,diskSizeGb]" -o tableBefore deleting, snapshot a volume you are unsure about, tag it with a deletion date, and tell the team. If nobody claims it in two weeks, delete the volume and keep the snapshot for a further month. For S3, add a lifecycle rule with AbortIncompleteMultipartUpload after seven days, and set log retention to what you actually need, often 30 or 90 days.
Step 3: rightsize on real utilisation Most servers and databases were sized for a launch, a load test or a guess. Rightsizing means matching them to what they really use. Look at at least two weeks of data, and a month if the workload has weekly or month-end peaks. AWS Compute Optimizer and Azure Advisor both produce recommendations; treat them as a starting list, not an instruction.
Check memory, not just CPU. On AWS, EC2 memory metrics need the CloudWatch agent, so without it a server can look idle while it is close to swapping. Look at peak and 95th percentile, not the average. A database at 10 percent average CPU may hit 90 percent during the nightly report. Move one size down at a time, and keep the old size noted for rollback. Resize staging first, then production in a quiet window. Instance resizes need a stop and start, and managed database changes can cause a failover or restart. Consider newer generations and ARM. Moving to a current instance family, or to Graviton on AWS where your stack supports arm64, usually costs less for the same work. Test container images and native dependencies first. Two quieter items belong here. Convert gp2 EBS volumes to gp3: it is cheaper per GB, includes a 3,000 IOPS and 125 MiB/s baseline, and the change happens online without detaching the volume. And check the versions you run. Managed databases and Kubernetes control planes on old major versions can fall into paid extended support on both AWS RDS and EKS, which quietly adds a charge on top of the normal price. Upgrading saves money and closes a security gap at the same time.
Step 4: fix data transfer and storage tiers Data transfer is the line item people understand least, and it often hides the largest surprise. Look for these patterns:
Private subnets reaching S3 or DynamoDB through a NAT gateway. NAT gateways charge per GB processed. Gateway VPC endpoints for S3 and DynamoDB have no hourly or data charge, and adding one is a route table change. Services that talk across availability zones all day. Cross-AZ traffic is billed per GB in each direction, so a chatty API in one zone and its cache in another adds up. Files, images and downloads served straight from instances or buckets. A CDN in front cuts origin egress and makes the site faster. Backups or logs copied out to another provider every night in full, where an incremental copy would do. For storage, use lifecycle rules to move objects that are rarely read to cheaper tiers, or S3 Intelligent-Tiering when access patterns are unknown. Be careful with archive tiers: they have minimum storage durations and retrieval charges, so they suit backups you hope never to read, not files users open.
Step 5: schedule and commit Non-production environments rarely need to run at night or at weekends. Stopping development and test servers outside working hours removes a large share of their running hours. A scheduled job with an instance scheduler, or a simple tag such as schedule=office-hours read by a small script, is enough. Note that a stopped RDS instance starts again automatically after seven days, so long pauses need a different plan, such as a snapshot and delete.
Only now, with waste removed and sizes settled, look at commitments. Compute Savings Plans on AWS and the Azure savings plan for compute trade a fixed hourly spend for one or three years against a lower rate, and they follow you across instance types. EC2 Instance Savings Plans, reserved instances and Azure reservations give deeper discounts but tie you to a specific instance family and region. Commit to the floor of your usage over the last few months, not the average, and review coverage every quarter. Spot instances and Azure Spot VMs suit work that can be interrupted at short notice (two minutes on AWS, 30 seconds on Azure), such as CI runners and batch jobs, not your primary database.
Keep it from growing back A one-off clean-up drifts back within a year unless something watches the bill. The guardrails we leave in place:
Budgets per account or subscription with alerts at forecast, not only at actual spend. AWS Cost Anomaly Detection or Azure cost anomaly alerts, routed to a channel someone reads. Required tags enforced through policy, so new resources arrive with an owner. A short monthly review: top five line items, what changed and why. Infrastructure defined in code, so a forgotten resource shows up as drift rather than a mystery. Checklist and when to get help Get three months of cost data grouped by service and owner. Tag everything with owner, environment and application. Find and remove unattached disks, old snapshots, idle IPs and unused environments, with a snapshot and notice period first. Set log retention and S3 lifecycle rules. Rightsize on two to four weeks of CPU and memory data, staging first. Move gp2 to gp3 and upgrade versions approaching extended support. Add gateway endpoints, review cross-AZ traffic and put a CDN in front of static files. Schedule non-production environments. Buy commitments for the steady floor only, and review them quarterly. Leave budgets and anomaly alerts running. Most teams can do the first half of this list in a week. It is worth bringing someone in when the bill spans several accounts or subscriptions, when nobody can say who owns the large line items, or when the remaining savings involve database changes or architecture, such as consolidating services or moving steady workloads off managed services. In those cases the risk is in the change, not the analysis, and a tested plan with rollback is worth more than another report.
Infigini IT Services · 11 Kanwali Road, Dehradun 248001, India · info@infigini.com · +91 95684 87789