Cloud cost optimization for startups: the first 90 days
Most startups do not have a cloud cost problem. They have a cloud waste problem. The difference matters. Here is what I find when I audit a startup's AWS or GCP bill in the first 90 days, what it actually costs, and what to fix before you hire anyone or switch providers.
A founder in Berlin sent me his AWS bill last June. His startup was four months old, pre-seed, three engineers. The bill was EUR 4,200 a month. He was running one API service, a Postgres database, and a frontend on a CDN. He thought the cost was normal. He thought this was what cloud infrastructure cost for a startup at his stage. He was wrong by a factor of four.
I audited the account in two hours. He had a Kubernetes cluster running twelve nodes, nine of which were idle. He had a managed Postgres instance sized for a workload ten times his actual traffic. He had three NAT gateways in regions where he ran nothing. He had CloudWatch logging enabled at full retention on services that logged 40GB a month of health check noise. He had a Load Balancer in front of a single instance. The list went on.
The bill dropped to EUR 980 a month after the audit. Same application. Same traffic. Same latency. Four things changed, none of them required a migration, a new tool, or a hire.
This is the pattern I see in almost every startup cloud bill I audit in the first 90 days. The costs are not driven by scale or complexity. They are driven by defaults, assumptions, and the fact that nobody looked at the bill until it was large enough to hurt.
The distinction that matters
Cloud cost optimization is not about spending less. It is about not spending money on things that provide no value. The EUR 4,200 bill was not buying the founder performance or reliability. It was buying him idle nodes, oversized databases, and logging he would never read. The EUR 980 bill bought him the same performance and reliability, because the things I removed were not contributing to either.
When founders tell me they need to optimize cloud costs, the first question I ask is: “What is the bill buying you?” If they cannot answer that question for 80% of the spend, the problem is not cost. The problem is visibility. You cannot optimize what you do not understand. The first 90 days of cloud cost optimization are 20% cutting waste and 80% understanding where the money goes.
Week one: understand the bill
Before you change anything, you need to know what you are paying for. This sounds obvious. It is not obvious to most founders. The AWS billing console is not designed for clarity. GCP is marginally better. Both bury the useful information under layers of aggregation that make it hard to see which specific resources are generating which specific costs.
The first thing I do is enable cost allocation tags. In AWS, this is a billing setting. In GCP, it is labels. The principle is the same: every resource gets a tag for environment (prod, staging, dev), team or service, and cost owner. Without tags, the bill is a lump sum. With tags, it is a breakdown.
# AWS: enable cost allocation tags in billing console, then tag everything
aws ec2 create-tags --resources i-0123456789abcdef \
--tags Key=Environment,Value=prod Key=Service,Value=api Key=Owner,Value=platform
# GCP: label resources
gcloud compute instances update api-prod-1 \
--update-labels environment=prod,service=api,owner=platform
Once tags are in place, I wait 24 hours for the cost data to populate, then I look at the breakdown. I am looking for three things: the top five cost categories, resources that are tagged but not used, and resources that are untagged (which usually means nobody is paying attention to them).
The untagged resources are the first candidates for review. In the Berlin founder’s account, there were fourteen untagged resources. Nine of them were idle EBS volumes from deleted instances. Three were old ECR repositories with images nobody had pulled in months. Two were Elastic IPs attached to nothing. Total cost of untagged waste: EUR 340 a month. That is the low-hanging fruit. It takes one afternoon to find and remove.
Week two: right-size what is running
After the obvious waste is gone, the next target is resources that are running but oversized. This is where most of the money hides in the first 90 days.
The database is usually the biggest offender. Founders pick database sizes based on guesswork or a tutorial they followed. The managed Postgres instance in the Berlin account was a db.r6g.2xlarge. That is 8 vCPUs and 64GB of RAM. The actual workload was 200 queries per minute with a working set of 2GB. A db.t4g.medium would have handled it with headroom. The difference was EUR 520 a month.
The way I right-size a database is not by guessing. I look at the CloudWatch or Cloud Monitoring metrics for the past two weeks. The metrics I care about are CPU utilization, database connections, freeable memory, and read/write IOPS. If CPU is below 20% and connections are below 30% of the max for a sustained period, the instance is oversized. I downgrade one size, watch the metrics for 48 hours, and repeat if the headroom is still there.
# AWS: check RDS metrics via CLI
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name CPUUtilization \
--dimensions Name=DBInstanceIdentifier,Value=prod-db \
--start-time 2026-07-13T00:00:00Z \
--end-time 2026-07-19T23:59:59Z \
--period 3600 \
--statistics Average,Maximum
# GCP: check Cloud SQL metrics
gcloud monitoring metrics list --filter="resource.type=cloudsql_database"
The same logic applies to compute instances and Kubernetes nodes. The Berlin founder’s EKS cluster had three m5.2xlarge nodes running nine pods that needed a total of 6 vCPUs and 12GB of memory. One m5.xlarge would have been enough. Two for redundancy. The cluster was paying for 36 vCPUs and using 6.
Kubernetes is particularly prone to this because the default node group configurations in EKS and GKE are generous. The managed node group wizard suggests instance types that are reasonable for production workloads at scale, not for a startup with three services and 200 requests per minute. I see this constantly. Founders create a cluster, accept the defaults, and never revisit the node types until the bill forces them to.
Right-sizing is not a one-time activity. It is a monthly review. I tell founders to put a calendar reminder on the first of every month: check the top five resources by cost, look at their utilization metrics, and downgrade anything with sustained headroom. This takes thirty minutes. It saves thousands of euros a year.
Weeks three through six: fix the architecture
Once waste is removed and resources are right-sized, the remaining costs are architectural. These are harder to fix because they require changing how the system is built, not just what it runs on.
The three architectural cost problems I see most often in the first 90 days:
NAT gateways in the wrong places
NAT gateways are cheap individually but expensive in aggregate. A startup running a VPC with three availability zones gets three NAT gateways by default in AWS. Each one costs EUR 32 a month plus data processing charges. If you are running in three AZs but your traffic is low, a single NAT gateway in one AZ with a route table that sends traffic from the other AZs through it is sufficient. This is a standard pattern. Most startups do not need multi-AZ NAT redundancy in the first 90 days.
I removed two of the three NAT gateways in the Berlin account. Savings: EUR 64 a month plus the data processing charges for two gateways handling traffic they did not need to handle. Total: EUR 110 a month.
Logging at the wrong granularity
The Berlin founder had CloudWatch Logs enabled on his API service with retention set to 90 days. The service logged every request, including health checks. The health checks ran every 10 seconds from the load balancer. That is 8,640 log entries per day per service, purely from health checks. At 40GB a month of log ingestion, the CloudWatch cost was EUR 180 a month.
The fix was two-fold. First, I changed the application to not log health check requests. This is a one-line change in most frameworks. Second, I reduced retention to 14 days. The founder did not need 90 days of logs. He needed enough to debug incidents, and 14 days covers that. If he needed longer retention for compliance, the logs would go to S3 with Glacier transition, which is a tenth of the CloudWatch cost.
# Log router filter for Kubernetes: drop health check logs
# Fluent Bit filter
[FILTER]
Name grep
Match app.*
Exclude log /GET \/healthz/
Load balancers for single-instance services
A startup running one instance of a service does not need a Load Balancer. It needs a static IP. The Load Balancer in front of the Berlin founder’s single API instance was costing EUR 18 a month in LB hours plus EUR 0.008 per GB of data processed. A single instance with an Elastic IP would have cost nothing for the IP and nothing for data processing. The tradeoff is that you lose the health check and failover behavior of the LB, but for a single instance, the LB’s health check just tells you the instance is dead. It does not give you a second instance to fail over to. The LB is paying for a feature you cannot use.
I replaced the LB with an Elastic IP and a simple health check script running on the instance that restarted the service if it stopped responding. The restart script took ten minutes to write. The LB removal saved EUR 30 a month.
Weeks seven through twelve: commit to what is stable
After the architecture is cleaned up, the remaining optimization is committing to the resources you know you need. This is where reserved capacity comes in.
AWS Reserved Instances and GCP Committed Use Discounts are the same concept: you commit to using a specific instance type for one or three years, and you get a discount of 30 to 60% compared to on-demand pricing. The catch is the commitment. If you commit to an instance type and then stop using it, you still pay for it.
The mistake I see is startups committing too early. In the first 90 days, your workload is changing. You are adding services, removing services, changing instance types. Committing to a one-year reservation in week four means you are locking in a decision you made before you had enough data. I tell founders to wait until the architecture has been stable for 30 days before committing. If the same instance type has been running for 30 days at the same utilization, it is safe to reserve. If the architecture is still changing, wait.
The resources worth committing to in the first 90 days are usually the database and the primary node group. These change rarely. The things not worth committing to are staging environments, dev instances, and experimental services. These come and go.
# AWS: purchase a reserved instance for the primary database
aws rds purchase-reserved-db-instances-offering \
--reserved-db-instances-offering-id <offering-id> \
--db-instance-count 1 \
--reservation-id prod-db-reservation
The math is straightforward. A db.t4g.medium on-demand costs EUR 0.034 per hour, or about EUR 25 per month. A one-year no-upfront reservation costs EUR 0.020 per hour, or about EUR 15 per month. On a single database, the saving is EUR 120 a year. On a cluster of five nodes, it is EUR 600 a year. Not life-changing for a funded startup, but it is free money for a decision that takes ten minutes.
The things I do not recommend in the first 90 days
There is a category of cost optimization that I actively tell startups to avoid in the first 90 days. Not because it does not work, but because the effort-to-savings ratio is wrong for a team that should be building product.
Spot instances for production workloads. Spot is 60 to 90% cheaper than on-demand, but your instances can be terminated with two minutes of notice. For batch jobs, CI runners, and stateless workloads that tolerate interruption, spot is excellent. For your production API, it is not worth the operational complexity in the first 90 days. I have seen startups save EUR 200 a month on spot and then lose EUR 5,000 in customer trust when their API went down during a spot reclamation event. Use spot for CI runners. Use on-demand for production. Revisit when you have multi-instance redundancy and a load balancer that handles termination gracefully.
Multi-cloud to reduce costs. The idea that spreading workloads across AWS and GCP reduces cost is wrong for startups. It increases cost, because you now pay for two cloud provider’s minimum commitments, two sets of egress charges, and the engineering time to maintain two sets of infrastructure. Multi-cloud is a vendor lock-in mitigation strategy, not a cost strategy. If cost is the goal, pick one provider and optimize within it.
FinOps tools. There are excellent FinOps platforms that give you detailed cost visibility, anomaly detection, and optimization recommendations. They cost EUR 500 to EUR 2,000 a month. For a startup spending EUR 1,000 a month on cloud, spending EUR 1,000 a month on a tool to manage that EUR 1,000 is not optimization. It is a different kind of waste. The native billing dashboards, cost explorer, and budget alerts in AWS and GCP are sufficient for any startup spending under EUR 10,000 a month. The FinOps tooling becomes worth it when your bill is large enough that a 5% optimization pays for the tool. That math kicks in around EUR 20,000 a month.
The monthly review that prevents regression
Cost optimization is not a project. It is a habit. The waste I removed from the Berlin account will come back if nobody is watching. New services get deployed with oversized defaults. Engineers spin up resources for testing and forget to tear them down. Logging gets enabled at full retention because nobody changed the default. The bill creeps up month over month until it hurts again.
The defense is a monthly review. Thirty minutes, first of every month. The checklist:
- Open the cost explorer. Filter by tag. Look at the top five resources by cost.
- Check utilization metrics for each. Downgrade anything with sustained headroom.
- Look for untagged resources. Tag or delete them.
- Review new resources created in the last 30 days. Confirm each one is intentional and right-sized.
- Check for idle resources. EBS volumes, EIPs, load balancers, old snapshots.
- Set a budget alert at 120% of expected monthly spend. If it fires, investigate immediately.
I have this checklist as a script that runs against the AWS Cost Explorer API and posts a summary to Slack. It takes me five minutes to review. It catches waste before it compounds. The founder in Berlin runs the same script. His bill has stayed between EUR 900 and EUR 1,100 for six months. The optimization held because the review is automatic.
What the first 90 days should cost
I am going to give you numbers, because founders respond to numbers and because I have audited enough startup cloud bills to know what is normal.
A pre-seed startup with one API service, a database, and a frontend should spend EUR 150 to EUR 400 a month on cloud infrastructure in the first 90 days. This assumes a single region, a small managed database, one or two compute instances, and a CDN for static assets. If the bill is above EUR 500, there is waste. If it is above EUR 1,000, there is a lot of waste.
A seed startup with three to five services, a Kubernetes cluster, and a managed database should spend EUR 400 to EUR 1,200 a month. The Kubernetes cluster adds node costs, the load balancer adds ingress costs, and the additional services add logging and monitoring costs. If the bill is above EUR 2,000, the cluster is likely oversized or the logging is uncontrolled.
A Series A startup with real traffic, multiple environments, and a production-grade observability stack should spend EUR 1,500 to EUR 5,000 a month, depending on traffic and data volume. Above EUR 5,000 at Series A with modest traffic, the cost is being driven by architectural decisions that need review, not by scale.
These are rough numbers. Workloads vary. But they are grounded in the accounts I have audited, and they are a useful sanity check. If your bill is significantly above these ranges and you cannot explain why, the explanation is almost certainly waste, not complexity.
The cost of optimizing too late
The founder in Berlin found me because his investor asked about the cloud bill. The investor had seen the EUR 4,200 monthly charge in the financials and asked whether it was justified. The founder did not know. He had never looked at the breakdown. He had been paying it for three months. He had spent EUR 12,600 on infrastructure that should have cost EUR 3,000. The EUR 9,600 difference was three months of runway. For a pre-seed startup, three months of runway is the difference between closing the next round and not.
The cost of optimizing too late is not the wasted spend. It is the compounding effect of that wasted spend over time. Waste that sits for three months is EUR 9,600. Waste that sits for six months is EUR 19,200. By the time the bill is large enough to demand attention, the accumulated waste is a number that would have meaningfully extended the startup’s runway. Cloud cost optimization is not about being frugal. It is about not burning runway on nothing.
The first 90 days of a startup’s cloud journey set the pattern for how the company thinks about infrastructure spend. If the pattern is “set it up and forget it,” the bill grows silently until it forces a conversation that nobody is prepared for. If the pattern is “understand what you are paying for and cut what provides no value,” the bill stays honest, and the runway goes further than it would have otherwise.
The work is not complicated. It is two hours of auditing, one afternoon of right-sizing, a few architectural fixes, and a monthly review that takes thirty minutes. None of it requires a hire. None of it requires a tool. It requires someone to look at the bill and ask the question the Berlin founder never asked: what is this buying me, and is it worth it?