Start with the boring wins
Before anyone proposes a re-architecture, check the unglamorous list. In almost every audit we run, the same items appear.
- Non-production environments running 24/7 when the team works 40 hours a week
- Instances sized for a launch-day traffic estimate that never materialised
- Snapshots and log archives with no lifecycle policy, growing quietly for years
- Load balancers and NAT gateways left behind by decommissioned services
- Data transfer between availability zones that a placement change would eliminate
Shutting down non-production overnight and at weekends alone typically removes 15–20% of a monthly bill. It takes an afternoon of scheduling work and it slows nobody down.
Then make spend visible
You cannot manage what nobody owns. Enforce a tagging policy - team, product, environment - and reject untagged resources at the infrastructure-as-code layer. Once every line item maps to a team, the conversation changes from "cloud is expensive" to "this service costs more than it earns."
Right-size on evidence
Pull two to four weeks of CPU, memory and IOPS data before resizing anything. Provisioned capacity based on peak-of-peaks is common and expensive. Autoscaling with a sensible floor usually beats a large fixed instance, provided your startup time is short enough to keep up with traffic.
Where to stop
Commitment-based discounts - reserved instances and savings plans - are worth taking on your genuinely steady baseline, and dangerous beyond it. Commit to the floor of your usage, not the average, and revisit quarterly.
Past that point, further savings usually mean architectural change: moving from always-on services to serverless, or from a managed database to a self-run one. Those trades cost engineering time and operational risk. Do the boring work first, and you may find you never need them.