Cost Optimization Guide
Optimize GCP costs with committed use discounts, preemptible VMs, and resource recommendations.
Prerequisites
- GCP project with billing access
- Familiarity with GCP compute and storage services
The Cost Optimization Mindset
Cost optimization on GCP is not about spending less; it is about spending smarter. The goal is to maximize the business value delivered per dollar of cloud spend. This requires continuous visibility into where money is going, why, and whether the spend is generating proportional value. A dollar saved on infrastructure that does not affect reliability or performance is pure profit margin improvement.
GCP provides several built-in tools for cost management: Billing Reports (visual dashboards), Cost Table (detailed breakdowns), Budgets & Alerts (proactive notifications), Recommender (automated optimization suggestions), and billing export to BigQuery (for custom analysis). The foundation of cost optimization is making these tools work for you before you make any changes to infrastructure.
Most organizations can reduce their GCP spend by 25-40% through basic optimization without any architectural changes. The key insight is that cloud waste accumulates silently: VMs left running after testing, storage growing unchecked, over-provisioned databases, and unused resources that no one remembers creating.
Export Billing to BigQuery First
Before doing anything else, enable billing export to BigQuery. This gives you access to line-item billing data that you can query, join with application metrics, and feed into custom dashboards. The console reports are useful but limited. BigQuery billing data is the single most powerful tool for understanding your GCP spend. It costs essentially nothing to store and query, and it enables analysis that is impossible with the console alone.
# Create a BigQuery dataset for billing data
bq mk --dataset \
--description="GCP Billing Export" \
--location=US \
my-project:billing_export
# Enable billing export in the Cloud Console:
# Billing > Billing export > BigQuery export > Edit settings
# Select the dataset created above
# Enable both "Standard usage cost" and "Detailed usage cost"
# Verify data is flowing (may take 24-48 hours)
bq query --use_legacy_sql=false '
SELECT
invoice.month,
SUM(cost) + SUM(IFNULL(credits.amount, 0)) AS net_cost
FROM `billing_export.gcp_billing_export_v1_XXXXXX`
LEFT JOIN UNNEST(credits) AS credits
GROUP BY 1
ORDER BY 1 DESC
LIMIT 6'Compute Cost Optimization
Compute Engine is typically the largest line item on a GCP bill, accounting for 40-60% of total spend for most organizations. The optimization strategies fall into four categories: right-sizing, scheduling, discount programs, and architectural changes.
Right-Sizing
The Recommender API analyzes 8+ days of VM utilization data and suggests smaller machine types when CPU or memory is consistently underutilized. On average, right-sizing recommendations save 20-40% on compute costs. This is the single highest-ROI optimization for most organizations because it requires no architectural changes.
# List all idle VM recommendations (VMs using <15% CPU)
gcloud recommender recommendations list \
--recommender=google.compute.instance.IdleResourceRecommender \
--project=my-project \
--location=us-central1-a \
--format="table(name, content.overview.resourceName, primaryImpact.costProjection.cost)"
# List machine type change recommendations
gcloud recommender recommendations list \
--recommender=google.compute.instance.MachineTypeRecommender \
--project=my-project \
--location=us-central1-a \
--format="table(content.overview.resourceName, content.overview.currentMachineType.name, content.overview.recommendedMachineType.name)"
# Aggregate savings across all zones in a project
for zone in $(gcloud compute zones list --format="value(name)" --filter="region:us-central1"); do
echo "=== $zone ==="
gcloud recommender recommendations list \
--recommender=google.compute.instance.MachineTypeRecommender \
--project=my-project \
--location=$zone \
--format="table(content.overview.resourceName, primaryImpact.costProjection.cost.units)" 2>/dev/null
doneValidate Before Downsizing
Right-sizing recommendations are based on observed peak utilization, which may not capture seasonal spikes. Always check at least 30 days of utilization data in Cloud Monitoring before downsizing. For critical production VMs, consider using custom machine types to match exact requirements rather than jumping to the next smaller predefined type. And always test the new size in staging before applying to production.
Scheduling Non-Production Resources
Development and staging environments often run 24/7 but are only used during business hours. Scheduling these VMs to stop at night and on weekends can reduce their compute cost by 65-75%. This is the second-highest ROI optimization after right-sizing.
# Create a Pub/Sub topic for VM management
gcloud pubsub topics create vm-schedule
# Stop dev VMs at 7 PM (weekdays)
gcloud scheduler jobs create pubsub stop-dev-vms \
--schedule="0 19 * * 1-5" \
--time-zone="America/Chicago" \
--topic=vm-schedule \
--message-body='{"action":"stop","label":"env=dev"}' \
--location=us-central1
# Start dev VMs at 7 AM (weekdays)
gcloud scheduler jobs create pubsub start-dev-vms \
--schedule="0 7 * * 1-5" \
--time-zone="America/Chicago" \
--topic=vm-schedule \
--message-body='{"action":"start","label":"env=dev"}' \
--location=us-central1
# Stop ALL non-production VMs on weekends
gcloud scheduler jobs create pubsub stop-weekend \
--schedule="0 20 * * 5" \
--time-zone="America/Chicago" \
--topic=vm-schedule \
--message-body='{"action":"stop","label":"env!=prod"}' \
--location=us-central1Committed Use Discounts
For workloads with predictable, steady-state compute needs, Committed Use Discounts (CUDs) offer significant savings. GCP CUDs are more flexible than AWS Reserved Instances because they apply to vCPU and memory amounts (not specific instance types), so you can change machine families without losing the discount.
| Commitment Term | Discount | Flexibility | Risk |
|---|---|---|---|
| 1 year | 37% | Applies to any machine type in the region | Lower; easier to predict 1 year of usage |
| 3 year | 57% | Same flexibility, longer lock-in | Higher; must be confident in long-term usage |
CUD Purchase Strategy
The key to CUD purchasing is to commit only to your baseline usage and let Sustained Use Discounts handle the variable portion.
-- Find minimum sustained vCPU and memory usage by region
-- This is the safe amount to commit to with CUDs
SELECT
location.region,
MIN(daily_vcpus) AS min_daily_vcpus,
AVG(daily_vcpus) AS avg_daily_vcpus,
MAX(daily_vcpus) AS max_daily_vcpus,
MIN(daily_memory_gb) AS min_daily_memory_gb
FROM (
SELECT
location.region,
DATE(usage_start_time) AS usage_date,
SUM(
CASE WHEN sku.description LIKE '%Core%'
THEN usage.amount_in_pricing_units ELSE 0 END
) AS daily_vcpus,
SUM(
CASE WHEN sku.description LIKE '%Ram%'
THEN usage.amount_in_pricing_units ELSE 0 END
) AS daily_memory_gb
FROM `billing_export.gcp_billing_export_v1_XXXXXX`
WHERE
service.description = 'Compute Engine'
AND usage_start_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)
GROUP BY 1, 2
)
GROUP BY 1
ORDER BY min_daily_vcpus DESCCUD Coverage Recommendations
GCP provides CUD coverage recommendations through the Recommender API. These recommendations analyze your usage patterns and suggest optimal CUD purchases. Access them via gcloud recommender recommendations list --recommender=google.compute.commitment.UsageCommitmentRecommender. A good rule of thumb: commit to 70-80% of your minimum sustained usage and let SUDs cover the rest.
Spot VMs for Fault-Tolerant Workloads
Spot VMs offer 60-91% discounts for workloads that can tolerate interruption. GCP can reclaim these VMs with 30 seconds notice. Ideal workloads include batch processing, CI/CD runners, distributed computing (Spark, Dataflow), rendering, and test environments.
# Example: 100 c2-standard-16 VMs for 8 hours of batch processing
# On-demand: 100 VMs * 16 vCPUs * $0.0388/vCPU-hr * 8 hrs = $497
# Spot: 100 VMs * 16 vCPUs * $0.0116/vCPU-hr * 8 hrs = $149
# Savings: $348 per batch run (70% savings)
# Create a Spot VM MIG for batch processing
gcloud compute instance-templates create batch-spot-template \
--machine-type=c2-standard-16 \
--provisioning-model=SPOT \
--instance-termination-action=DELETE \
--image-family=ubuntu-2404-lts \
--image-project=ubuntu-os-cloud \
--no-address \
--service-account=batch@my-project.iam.gserviceaccount.com
gcloud compute instance-groups managed create batch-mig \
--template=batch-spot-template \
--size=100 \
--zone=us-central1-aStorage Cost Optimization
Cloud Storage and persistent disk costs grow silently over time. Without active management, storage becomes the second largest cost driver. The key insight is that most data in storage is accessed infrequently but remains in expensive Standard class.
Cloud Storage Optimization
- Lifecycle policies: Automatically transition objects from Standard to Nearline (30 days), Coldline (90 days), and Archive (365 days). This alone can reduce storage costs by 40-60%.
- Autoclass: Let GCP automatically choose storage classes based on access patterns. Ideal when you cannot predict usage.
- Delete unused snapshots: VM disk snapshots accumulate over time. Set up automated cleanup of snapshots older than your retention requirement.
- Resize over-provisioned disks: GCP charges for provisioned disk size, not used space. A 500 GB SSD at 10% utilization costs the same as a 500 GB SSD at 90%.
- Use regional vs. multi-region wisely: Multi-region buckets cost 2x more than regional. Only use multi-region for data that needs geographic redundancy.
- Compress before storing: GCS charges per GB stored. Gzip or Zstandard compression can reduce log files by 80-90%.
Persistent Disk Optimization
# Find unattached persistent disks (paying for storage but not using them)
gcloud compute disks list \
--filter="NOT users:*" \
--format="table(name, zone, sizeGb, type, status)" \
--project=my-project
# Find snapshots older than 90 days
gcloud compute snapshots list \
--filter="creationTimestamp<-P90D" \
--format="table(name, diskSizeGb, creationTimestamp, storageBytes)" \
--project=my-project
# Calculate total cost of unattached disks
gcloud compute disks list \
--filter="NOT users:*" \
--format="value(sizeGb)" \
--project=my-project | \
awk '{sum += $1} END {printf "%.2f GB unattached, ~$%.2f/month (SSD)
", sum, sum * 0.17}'Disk Type Matters for Cost
pd-standard (HDD) costs $0.04/GB/month. pd-balanced (SSD) costs $0.10/GB/month. pd-ssd costs $0.17/GB/month. For workloads that do not need high IOPS (log storage, cold data, backups), switching from pd-ssd to pd-standard can save 75%. Check IOPS requirements before changing disk types: pd-standard provides only 0.75 read IOPS per GB and 1.5 write IOPS per GB.
Network Egress Optimization
Network egress (data leaving GCP to the internet or to other clouds) is often an overlooked cost driver. GCP charges $0.08-0.12 per GB for internet egress on Premium Tier. For services transferring terabytes of data, egress costs can exceed compute costs.
| Egress Type | Cost | Optimization Strategy |
|---|---|---|
| Internet egress (Premium) | $0.08-0.12/GB | Use Cloud CDN, compress responses, use Standard Tier |
| Internet egress (Standard) | $0.045-0.08/GB | Use for non-latency-sensitive workloads |
| Cross-region (same VPC) | $0.01/GB | Co-locate services in the same region |
| Same-region (same zone) | Free | Keep communicating services in the same zone |
| To Google APIs | Free | Use Private Google Access (no NAT charges) |
| Cloud Interconnect | $0.02/GB | Much cheaper than internet egress for hybrid workloads |
SELECT
project.id AS project_id,
service.description AS service,
sku.description AS sku,
SUM(cost) AS total_cost,
SUM(usage.amount) AS total_usage_gb
FROM `billing_export.gcp_billing_export_v1_XXXXXX`
WHERE
invoice.month = FORMAT_DATE('%Y%m', CURRENT_DATE())
AND sku.description LIKE '%Egress%'
GROUP BY 1, 2, 3
ORDER BY total_cost DESC
LIMIT 20CDN for Egress Reduction
Cloud CDN can dramatically reduce egress costs for content-heavy applications. CDN cache hits serve content from Google's edge network, which is charged at CDN egress rates ($0.02-0.08/GB) instead of origin egress rates. For a 90% cache hit rate, you can reduce egress costs by 70-80%.
GCP Networking Deep DiveServerless Cost Optimization
Serverless services (Cloud Run, Cloud Functions, BigQuery) charge per use, which sounds efficient but can become expensive without attention. The key to serverless cost optimization is understanding the pricing model and configuring services to minimize waste.
Cloud Run Optimization
- Set concurrency appropriately: Each concurrent request shares the same instance cost. Setting concurrency to 50-200 for I/O-bound workloads means one instance handles many requests, dramatically reducing cost per request.
- Use CPU-only-during-request: Use
--cpu-throttling(default) instead of--no-cpu-throttlingunless you need background processing. This can cut costs by 50% because idle instances use minimal CPU. - Set min instances carefully: Each min instance costs about 10% of an active instance. Only set min instances above 0 when cold start latency is unacceptable.
- Right-size CPU and memory: Start with the minimum (1 CPU, 256 MB) and increase only if needed. Over-provisioning serverless resources is common because there is no right-sizing recommender for Cloud Run.
BigQuery Optimization
- Use partitioned tables: Partition tables by date and cluster by frequently filtered columns. This reduces the amount of data scanned per query, directly reducing cost on on-demand pricing.
- Switch to editions pricing: For organizations scanning more than 5 TB/month, BigQuery Editions with autoscaling slots often saves 50-70% compared to on-demand ($5/TB scanned).
- Use materialized views: Pre-compute common aggregations to avoid rescanning raw data.
- Audit query patterns: Use INFORMATION_SCHEMA.JOBS to find the most expensive queries and optimize them with partitioning, clustering, or query restructuring.
-- Top 20 most expensive queries in the last 30 days
SELECT
user_email,
job_id,
ROUND(total_bytes_processed / POW(1024, 4), 2) AS tb_processed,
ROUND(total_bytes_processed / POW(1024, 4) * 5, 2) AS estimated_cost_usd,
query,
creation_time
FROM `region-us`.INFORMATION_SCHEMA.JOBS
WHERE
creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
AND job_type = 'QUERY'
AND state = 'DONE'
AND total_bytes_processed > 0
ORDER BY total_bytes_processed DESC
LIMIT 20Set Up Billing Alerts
Create budget alerts at 50%, 80%, and 100% of your expected monthly spend. Send alerts to both email and a Pub/Sub topic so you can trigger automated responses (like shutting down non-critical resources) when spend exceeds thresholds. Budget alerts have zero cost and are the simplest way to prevent bill shock. You can create budgets per project, per folder, or for the entire billing account.
Database Cost Optimization
Database services (Cloud SQL, Spanner, AlloyDB, Firestore) are often the third-largest cost category after compute and storage.
Cloud SQL Optimization
- Right-size instances: Cloud SQL provides built-in monitoring. If CPU rarely exceeds 50%, downsize. If memory usage is consistently under 60%, reduce memory.
- Stop development databases overnight: Unlike production databases, dev/staging databases can be stopped outside business hours using Cloud Scheduler.
- Use read replicas wisely: Read replicas cost the same as the primary instance. Only create them if you genuinely need read scaling or cross-region read access.
- Consider Cloud SQL Enterprise edition: The Enterprise edition offers better price-performance for production workloads compared to Enterprise Plus.
Firestore Cost Control
- Use aggregation queries: Count and sum operations read index entries, not full documents, which is much cheaper.
- Maintain denormalized aggregates: Instead of reading 10,000 documents to compute a total, maintain a single aggregation document updated by Cloud Functions.
- Exempt unused fields from indexing: Each indexed field adds to write cost and storage. Exempt large text fields and arrays that are never queried.
- Set TTLs on ephemeral data: Use Firestore's TTL feature to automatically delete sessions, temporary tokens, and other short-lived documents.
Labeling Strategy for Cost Allocation
Labels are the foundation of cost allocation in GCP. Without consistent labels, you cannot answer basic questions like “how much does Team A spend?” or “what percentage of our bill is production vs. development?”
| Label Key | Purpose | Example Values |
|---|---|---|
team | Cost allocation by team | platform, data, frontend, ml |
env | Identify environment | prod, staging, dev, sandbox |
cost-center | Financial tracking | cc-1234, engineering, marketing |
service | Identify the application | api, web, worker, analytics |
managed-by | Track IaC vs. manual resources | terraform, manual, pulumi |
# Check for unlabeled resources in Terraform CI pipeline
terraform plan -out=tfplan
terraform show -json tfplan | jq '
.resource_changes[]
| select(.change.actions[] == "create")
| select(.change.after.labels == null
or (.change.after.labels | has("team") | not)
or (.change.after.labels | has("env") | not))
| .address' -r-- Monthly costs broken down by team and environment labels
SELECT
labels.value AS team,
(SELECT value FROM UNNEST(labels) WHERE key = 'env') AS environment,
SUM(cost) + SUM(IFNULL((SELECT SUM(amount) FROM UNNEST(credits)), 0)) AS net_cost
FROM `billing_export.gcp_billing_export_v1_XXXXXX`
LEFT JOIN UNNEST(labels) AS labels ON labels.key = 'team'
WHERE
invoice.month = FORMAT_DATE('%Y%m', CURRENT_DATE())
GROUP BY 1, 2
ORDER BY net_cost DESCAutomated Cost Governance
Manual cost optimization does not scale. Implement automated guardrails and alerts to catch waste before it accumulates.
Budget Alerts with Automated Response
# Create a Pub/Sub topic for budget alerts
gcloud pubsub topics create budget-alerts
# Create a budget with alerts (via gcloud)
gcloud billing budgets create \
--billing-account=BILLING_ACCOUNT_ID \
--display-name="Production Monthly Budget" \
--budget-amount=10000 \
--threshold-rule=percent=0.5 \
--threshold-rule=percent=0.8 \
--threshold-rule=percent=1.0 \
--notifications-rule-pubsub-topic=projects/my-project/topics/budget-alerts \
--filter-projects=projects/prod-project-1,projects/prod-project-2
# Deploy a Cloud Function to handle budget alerts
# (stop non-critical resources when budget exceeds threshold)
gcloud functions deploy budget-enforcer \
--gen2 \
--runtime=python312 \
--trigger-topic=budget-alerts \
--entry-point=handle_budget_alert \
--service-account=budget-enforcer@my-project.iam.gserviceaccount.comRecommender API Automation
#!/bin/bash
# Run weekly via Cloud Scheduler + Cloud Function
echo "=== Cost Optimization Report ==="
echo ""
# Right-sizing recommendations
echo "## VM Right-Sizing Recommendations"
for zone in $(gcloud compute zones list --format="value(name)" --filter="status=UP"); do
gcloud recommender recommendations list \
--recommender=google.compute.instance.MachineTypeRecommender \
--project=my-project \
--location=$zone \
--format="csv(content.overview.resourceName,primaryImpact.costProjection.cost.units)" 2>/dev/null
done | sort -t',' -k2 -rn | head -20
echo ""
echo "## Idle Resources"
for zone in $(gcloud compute zones list --format="value(name)" --filter="status=UP"); do
gcloud recommender recommendations list \
--recommender=google.compute.instance.IdleResourceRecommender \
--project=my-project \
--location=$zone \
--format="csv(content.overview.resourceName)" 2>/dev/null
done
echo ""
echo "## Unattached Disks"
gcloud compute disks list \
--filter="NOT users:*" \
--format="table(name, zone, sizeGb)" \
--project=my-projectDo Not Automate Cost Cuts in Production
Automated responses to budget alerts should only affect non-production resources. Never automatically stop or delete production VMs, databases, or services based on budget thresholds. Instead, use alerts to notify the appropriate team, who can make informed decisions about which resources to optimize. Automated shutdown of production resources is a common cause of self-inflicted outages.
Building a Cost Optimization Practice
Cost optimization is not a one-time project; it is an ongoing practice. Establish these habits to maintain cost efficiency over time:
Cadence
- Weekly (10 minutes): Review the Recommender dashboard for new right-sizing and idle resource suggestions.
- Monthly (1 hour): Review billing reports by project and service. Compare month-over-month spend and investigate any increases greater than 10%.
- Quarterly (half day): Evaluate CUD purchases. Review storage lifecycle effectiveness. Audit network egress patterns. Check Spot VM utilization for batch workloads.
- Annually: Review overall cloud architecture for cost-saving opportunities. Evaluate serverless vs. VM workloads. Renegotiate Google Cloud contracts if applicable.
Cost Optimization Checklist
| Area | Optimization | Typical Savings |
|---|---|---|
| Compute | Right-size VMs based on Recommender | 20-40% |
| Compute | CUDs for stable workloads | 37-57% on committed portion |
| Compute | Spot VMs for batch workloads | 60-91% |
| Compute | Schedule non-prod resources | 65-75% on those resources |
| Storage | Lifecycle rules / Autoclass | 40-60% on storage costs |
| Storage | Delete unattached disks and old snapshots | 100% on those resources |
| Network | Cloud CDN for content delivery | 50-80% on egress costs |
| Network | Standard Tier for non-prod | 25-40% on egress |
| Serverless | Optimize Cloud Run concurrency | 10-50x per-request cost reduction |
| BigQuery | Partitioning and clustering | 50-90% on query costs |
Cost Optimization ROI
Most organizations can reduce their GCP spend by 25-40% through basic optimization. Start with the largest line items first for maximum impact: right-size the biggest VMs, apply lifecycle rules to the largest storage buckets, and purchase CUDs for your most stable workloads. Track savings month-over-month in a dashboard to demonstrate the value of cost optimization efforts to leadership.
Key Takeaways
- 1Committed Use Discounts (CUDs) save up to 57% on compute for 1-year and 70% for 3-year terms.
- 2Spot VMs offer up to 91% savings for fault-tolerant workloads.
- 3Sustained Use Discounts automatically apply after 25% monthly usage with no commitment needed.
- 4Active Assist and Recommender identify idle resources, right-sizing opportunities, and unused IPs.
- 5Export billing data to BigQuery for custom cost analysis and anomaly detection.
- 6Set budget alerts and quotas to prevent unexpected spending.
Frequently Asked Questions
What are Committed Use Discounts (CUDs)?
How do Sustained Use Discounts work?
What is the difference between Spot VMs and preemptible VMs?
How do I find unused or idle GCP resources?
How should I set up GCP billing alerts?
Written by CloudToolStack Team
Cloud engineers and architects with hands-on experience across AWS, Azure, and GCP. We write guides based on real-world production patterns, not just documentation rewrites.
Disclaimer: This guide is for educational purposes. Cloud services change frequently; always refer to official documentation for the latest information. AWS, Azure, and GCP are trademarks of their respective owners.