The over-provisioning problem
Most cloud bills are 30–50% higher than they need to be. The cause is almost always the same: infrastructure was provisioned for a peak load that either never came or lasted two hours on a Tuesday, and nobody went back to right-size it.
It’s understandable. When the production database is slow, the instinct is to upgrade the instance size. When traffic spikes, you add capacity. But the reverse , scaling back down , rarely happens with the same urgency. After twelve months of "just bump it up," you’re running an m6i.4xlarge for a workload that fits comfortably on an m6i.xlarge.
Step 1: audit and measure
Before changing anything, you need visibility. Most teams don’t know which services cost what or why.
Cost allocation tagging. Tag every resource with at minimum: team, environment, and service. This takes a day to implement and permanently changes your ability to answer "why is our bill so high?"
Usage metrics collection. For every compute instance, track average CPU utilisation, memory usage, and network throughput over 30 days. The data tells you exactly what’s over-provisioned.
The audit typically reveals:
- Development and staging environments running 24/7 when they’re only used during business hours
- Database instances sized for a load they haven’t seen in months
- Orphaned resources: load balancers with no targets, EBS volumes detached from instances, snapshots nobody needs
- Data transfer costs from architecture decisions made early and never revisited
Step 2: quick wins (week 1)
These changes can be made immediately with minimal risk:
Delete orphaned resources. Unattached EBS volumes, unused Elastic IPs, old snapshots, and empty S3 buckets. We’ve seen $500–$2,000/month recovered from cleanup alone.
Schedule non-production environments. Development and staging servers don’t need to run at 2am. Schedule them to start at 7am and stop at 7pm on weekdays. Immediate 60% cost reduction for those environments.
Enable S3 lifecycle policies. Move infrequently accessed data to S3 Infrequent Access after 30 days and Glacier after 90 days. Storage costs drop 50–80% for archived data.
Review data transfer. A surprising amount of cloud spend is inter-region or internet-egress data transfer. Check whether services that talk to each other are in the same region and availability zone.
Step 3: right-sizing (weeks 2–4)
Right-sizing means matching instance sizes to actual utilisation. This is where the largest savings live.
Compute instances. If your EC2 instance averages 15% CPU utilisation over 30 days, it’s at least one size too large. Downsize, monitor for a week, and adjust if needed. For most workloads, targeting 40–60% average utilisation is the sweet spot.
Database instances. RDS instances are often the most over-provisioned. A db.r6g.2xlarge running at 20% CPU with 30% memory utilisation should be a db.r6g.large. Enable Performance Insights to verify the smaller instance handles your query patterns.
Graviton migration. AWS Graviton (ARM-based) instances are 20–40% cheaper than equivalent x86 instances with comparable performance. Most applications run without modification on Graviton. Test, then migrate.
Step 4: commitment-based discounts
Once you know your baseline, lock in discounts for predictable workloads:
Reserved Instances / Savings Plans. Commit to 1-year or 3-year terms for workloads that run continuously. Savings of 30–60% compared to on-demand pricing. Only commit to what you’ll definitely use , the discount isn’t worth it if you over-commit.
Spot Instances. For fault-tolerant workloads (batch processing, CI/CD, stateless web servers behind a load balancer), spot instances offer 60–90% discounts. Use spot fleet with multiple instance types and availability zones for reliability.
Step 5: architectural optimisation
The biggest cost savings come from architectural changes, not just right-sizing:
Serverless for variable workloads. Lambda, Cloud Functions, or Azure Functions cost nothing when idle and scale automatically under load. API endpoints that handle 100 requests per hour don’t need a dedicated server.
CDN and caching. Cloudflare or CloudFront in front of your application caches static assets and common API responses at the edge. Reduces both latency and origin server load. A properly configured CDN can reduce compute costs by 30–50%.
Database query optimisation. A single unindexed query running thousands of times per day can force you to run a larger database instance than necessary. Adding the right indexes is free and often eliminates the need for a larger instance.
Connection pooling. PostgreSQL connections are expensive. Without connection pooling (PgBouncer or RDS Proxy), your database instance needs to be sized for peak connection count rather than peak query load. Pooling typically allows a 50% smaller instance.
Ongoing management
Cost optimisation isn’t a one-time project. Without ongoing monitoring, costs creep back up within 3–6 months.
Set up cost alerts. AWS Budgets or GCP Budget alerts when spending exceeds thresholds. Alert at 80% and 100% of expected monthly spend.
Monthly cost reviews. A 30-minute monthly review of the top 10 cost drivers catches drift early. Compare against the previous month and investigate any increase above 10%.
Automated right-sizing recommendations. AWS Compute Optimizer and GCP Recommender continuously analyse utilisation and suggest changes. Review their recommendations weekly.
Real numbers
Here’s what this playbook has achieved for ELASYN clients:
- Logistics SaaS platform: $45,000/month → $18,000/month (60% reduction). Primary savings: right-sizing RDS, spot instances for background processing, scheduling staging environments.
- E-commerce platform: $12,000/month → $7,500/month (37% reduction). Primary savings: CDN caching, S3 lifecycle policies, Graviton migration.
- Healthcare data platform: $28,000/month → $16,000/month (43% reduction). Primary savings: reserved instances, connection pooling, query optimisation that allowed a smaller database instance.
Every engagement pays for itself within the first two months of savings.