What If We Ran on AWS or Google Cloud?
Every production Azure resource priced against its named AWS and Google Cloud equivalent — from the live resource inventory and the published rate cards, not a vendor calculator
The Question, and What This Is Not
Grade My Investments runs on Azure. That was a deliberate choice — the stack is .NET end to end, the team knew Azure, and the tooling fit. But "we picked it and never looked again" is not an engineering position, it's a habit. So this page does the arithmetic: what would the identical system cost on Amazon Web Services and on Google Cloud?
This is a priced thought experiment, not a migration plan. Nothing here is a recommendation to move, and the conclusion is not "cloud X is cheapest." The interesting result turned out to be somewhere else entirely — see what the numbers actually say.
flowchart TB
subgraph AZ[Azure - in production today]
A1[App Service B1 Windows<br/>4 static front-ends]
A2[Azure Functions<br/>App Service B1 Linux]
A3[MySQL Flexible B1ms]
A4[Virtual Machine B2s<br/>16 background services]
A5[Blob Storage]
end
subgraph AWS[Amazon Web Services]
B1[S3 + CloudFront]
B2[Lambda + API Gateway]
B3[RDS for MySQL<br/>db.t4g.small]
B4[EC2 t4g.medium<br/>Graviton]
B5[S3]
end
subgraph GCP[Google Cloud]
C1[Cloud Storage + Cloud CDN]
C2[Cloud Run]
C3[Cloud SQL for MySQL<br/>db-g1-small]
C4[Compute Engine e2-medium]
C5[Cloud Storage]
end
A1 --- B1 --- C1
A2 --- B2 --- C2
A3 --- B3 --- C3
A4 --- B4 --- C4
A5 --- B5 --- C5How These Numbers Were Produced
The Azure column is not an estimate. It comes from two live sources: the actual resource
inventory of the gmiapp-prod-rg resource group, and the
Azure Retail
Prices API, which returns the same public rate card the portal quotes. Those figures were
then reconciled against the real invoice via the Cost Management API, broken out per meter and
per resource. The AWS and Google figures are published list prices for the equivalent SKUs.
| Assumption | Value | Why |
|---|---|---|
| Pricing date | 27 August 2026 | All three rate cards read the same day |
| Regions | Azure Central US · AWS us-east-2 (Ohio) · GCP us-central1 (Iowa) | Geographically comparable Midwest regions, all three vendors' low-cost tier |
| Month | 730 hours | The convention all three vendors use |
| Discounts | None applied | List price only — no reserved instances, savings plans, committed-use discounts, or enterprise agreements. All three offer 30–60% off for 1–3 year commitments, which compresses the totals but barely moves the ranking |
| Free tiers | Applied only where permanent | CloudFront's 1 TB / 10M requests and Google's 50 GiB of logs are standing allowances, not 12-month trials, so they count |
| Egress | Excluded | Real bandwidth cost last month was $0.12. At GMI's volume it is noise on every cloud; at scale it is the line that would decide the answer |
Excluded throughout because they are cloud-agnostic and would not change: the market-data license ($50/month minimum), the Anthropic API, Twilio messaging, domain registration, and Azure DevOps. Those follow the platform wherever it runs.
Service Equivalence Matrix
Every Azure service in the platform, named alongside what it would be called on the other two clouds. Rows marked in use are live in production today; the rest are what the corresponding capability is built from instead.
| Layer | Azure (in use) | AWS equivalent | Google Cloud equivalent |
|---|---|---|---|
| Compute & hosting | |||
| Static site hosting in use | App Service (Windows B1) — Static Web Apps would fit | S3 + CloudFront, or Amplify Hosting | Cloud Storage + Cloud CDN, or Firebase Hosting |
| Serverless API in use | Azure Functions (isolated worker) | Lambda + API Gateway (HTTP API) | Cloud Run functions |
| Container / PaaS host | App Service (Linux) | App Runner, or Elastic Beanstalk | Cloud Run, or App Engine |
| Batch VM in use | Virtual Machines (B-series burstable) | EC2 (t3 / t4g Graviton) | Compute Engine (e2) |
| Data | |||
| Managed MySQL in use | Azure Database for MySQL — Flexible Server | RDS for MySQL, or Aurora MySQL | Cloud SQL for MySQL |
| Object storage in use | Blob Storage (ZRS + LRS) | S3 (Standard / One Zone-IA) | Cloud Storage (Standard / Nearline) |
| Block storage in use | Managed Disks (Premium SSD P4) | EBS (gp3) | Persistent Disk (balanced) |
| Job queue in use | MySQL table — no queue product rented | SQS | Pub/Sub |
| Security & identity | |||
| Secret storage in use | Key Vault | Secrets Manager, or SSM Parameter Store | Secret Manager |
| Workload identity in use | Managed Identity | IAM roles (instance profiles) | Service accounts / Workload Identity |
| Private networking in use | Virtual Network + NSG | VPC + security groups | VPC + firewall rules |
| TLS certificates in use | App Service managed certificates | AWS Certificate Manager | Google-managed SSL certificates |
| Delivery & operations | |||
| CDN | Front Door / Azure CDN | CloudFront | Cloud CDN |
| DNS | Azure DNS | Route 53 | Cloud DNS |
| APM / tracing in use | Application Insights | CloudWatch + X-Ray | Cloud Monitoring + Cloud Trace |
| Log aggregation in use | Log Analytics | CloudWatch Logs | Cloud Logging |
| CI/CD in use | Azure DevOps Pipelines | CodePipeline + CodeBuild | Cloud Build |
| Infrastructure as code in use | Pulumi (Azure Native provider) | Pulumi (AWS provider), or CloudFormation | Pulumi (GCP provider), or Config Controller |
| Container registry | Azure Container Registry | Elastic Container Registry | Artifact Registry |
| Intelligence & messaging | |||
| Forecasting in use | ML.NET, in-process — no ML service rented | SageMaker | Vertex AI |
| LLM analysis in use | Anthropic API direct | Bedrock | Vertex AI |
| Transactional email in use | SendGrid | SES | No first-party service |
| SMS in use | Twilio | SNS / End User Messaging | No first-party service |
Three rows are worth reading twice. The job queue, the ML runtime, and the LLM integration are all capabilities the platform has without renting a product for them — a MySQL table, an in-process library, and a direct HTTPS call. On every cloud in this table those would otherwise be three more line items and three more vendor dependencies.
Scenario A — Lift and Shift
The same shapes, moved as-is: always-on managed hosts for the front-ends and the API, a managed MySQL server, one always-on batch VM. No re-architecture. This is the honest comparison, because it is the one that requires no rewriting.
| Workload | Azure — today | AWS | Google Cloud |
|---|---|---|---|
| Four front-ends www, app, admin, tech |
App Service Plan B1 Windows $54.75 |
Elastic Beanstalk, t3.small + IPv4 $18.83 |
Compute Engine e2-small + IP $15.15 |
| API host ~350 endpoints, always on |
App Service Plan B1 Linux $13.14 |
Elastic Beanstalk, t3.small $15.18 |
Cloud Run, min-instances=1 $24.60 |
| MySQL 1 vCPU / 2 GB, 32 GB, 35-day backup |
Flexible Server B1ms compute $14.02 · storage $4.16 · paid IO $14.50 $32.68 |
RDS db.t4g.small + 32 GB gp3 compute $23.36 · storage $3.68 $27.04 |
Cloud SQL db-g1-small + 32 GB SSD compute $26.00 · storage $5.44 $31.44 |
| Batch VM 16 background services, 2 vCPU / 4 GB |
Standard_B2s + P4 disk + IP $44.34 |
EC2 t3.medium + gp3 + IPv4 $36.58 |
Compute Engine e2-medium + PD + IP $30.58 |
| Object storage | Blob (ZRS + LRS) ~$1.00 |
S3 Standard ~$1.00 |
Cloud Storage Standard ~$1.00 |
| Secrets 12 secrets |
Key Vault $0.05 |
Secrets Manager $4.80 (Parameter Store: $0) |
Secret Manager $0.72 |
| Telemetry | Application Insights ~$1.00 |
CloudWatch ~$3.00 |
Cloud Ops (50 GiB free) $0.00 |
| Networking | VNet + NSG $0.10 |
VPC + security groups $0.00 |
VPC + firewall rules $0.00 |
| Monthly total | ~$147 | ~$106 | ~$104 |
AWS lands about 28% below the current Azure bill and Google about 29% below — roughly $500 a year either way. That is a real number, but it is not the largest number on this page.
Scenario B — Built the Way Each Cloud Wants
Now allow re-architecture: the four front-ends are already static files, so they belong on object storage behind a CDN, not on a rented always-on host. The API becomes request-billed instead of always-on. The database and the batch VM are unchanged, because neither has a serverless shape that fits.
| Workload | Azure | AWS | Google Cloud |
|---|---|---|---|
| Four front-ends | Static Web Apps, Free tier $0.00 |
S3 + CloudFront + ACM ~$0.50 |
Cloud Storage + external ALB + CDN $18.25 (fixed floor) |
| API | Functions, Consumption plan ~$1.00 |
Lambda + API Gateway HTTP ~$2.00 |
Cloud Run, scale to zero ~$1.00 |
| MySQL (unchanged) | $32.68 | $27.04 | $31.44 |
| Batch VM (ARM where offered) | Standard_B2s + disk + IP $44.34 |
EC2 t4g.medium Graviton + gp3 + IPv4 $30.74 |
Compute Engine e2-medium + PD + IP $30.58 |
| Storage, secrets, telemetry, network | ~$2.15 | ~$4.00 (Parameter Store, not Secrets Manager) | ~$1.72 |
| Monthly total | ~$80 | ~$64 | ~$83 |
Note what happens to Google Cloud here: it wins Scenario A and loses Scenario B, because its external load balancer bills roughly $18.25/month for the first five forwarding rules whether anyone visits or not. Five custom domains means paying that toll on day one. CloudFront charges no fixed fee at all and includes 1 TB of egress and 10 million requests every month, permanently. Azure Static Web Apps' free tier covers this workload outright. For a small static estate, the CDN billing model matters more than the compute rate.
What the Numbers Actually Say
1. The architecture gap is bigger than the vendor gap
Between the cheapest cloud and the most expensive, the spread is about $43/month. Between the current architecture and a better one on the cloud already in use, the spread is about $67/month. The lever that matters is not the logo on the invoice. Anyone who answers "our cloud is too expensive" by shopping vendors is optimising the smaller of the two numbers.
2. The single worst line item is a Windows licence nothing needs
The most expensive resource in production is an App Service Plan running Windows at $54.75/month. The identical plan on Linux is $13.14 — the other $41.61 is the Windows licence. What it hosts is four sets of static files. Neither AWS nor Google has an equivalent premium here, not because they are cheaper, but because nothing in this workload was ever going to need Windows. That is a provisioning mistake, and it costs more per year than switching clouds would save.
3. A meter nobody had counted
Reading the invoice per-meter rather than per-service surfaced
Paid IO LRS IO Rate Operations billed against the MySQL server at roughly
$14.50/month — almost exactly what the database compute costs.
Burstable MySQL tiers meter storage IO separately, and it had never appeared in any estimate
because service-level totals hide it inside "Azure Database for MySQL." The real run rate is
~$147/month, not the ~$125 previously carried. AWS and Google both fold
baseline IOPS into the gp3 / persistent-disk rate, so the equivalent line simply does not exist
on either — worth about $170/year on its own.
4. Azure wins the database, loses the compute
Managed MySQL compute is genuinely cheapest on Azure: $14.02 for B1ms against
$23.36 for RDS db.t4g.small and $26.00 for Cloud
SQL db-g1-small. That advantage is then given straight back at the paid-IO meter.
On raw compute the position reverses — the same 2 vCPU / 4 GB batch machine is
$36.43 on Azure, $24.53 on AWS Graviton, and
$24.46 on Google. ARM is the difference: Azure's burstable B-series has no
Graviton-class equivalent at this size, and the workload is portable .NET that would run on ARM
without modification.
5. Nothing here is locked in — on purpose
The reason this comparison is even possible to compute is that the platform never adopted a proprietary datastore. It is MySQL, which all three clouds sell. The job queue is a database table, not a queue product. Forecasting is an in-process library, not a hosted ML endpoint. Blob access is behind a single interface seam. Those choices were made for simplicity and cost, and portability came free as a side effect — which is the reverse of how most "multi-cloud strategies" are sold.
What Would Actually Have to Be Rewritten
The bill is the easy half. A cost comparison that stops at the rate card is worthless, because the migration is paid in engineering time, not instance-hours. Honest inventory of the work:
| Component | Portability | What it would take |
|---|---|---|
| Blazor WebAssembly front-ends | Portable as-is | Static output. Copy the files to a bucket. Genuinely zero work. |
| MySQL schema and data | Portable as-is | A dump and a restore. Same engine, same version, all three clouds. |
| Background console services | Portable as-is | Plain .NET processes under systemd on a Linux VM. The VM changes name; nothing else does. |
| Blob storage access | One seam | All access already routes through a single IBlobStorageService interface. One new implementation against the S3 or GCS SDK — the abstraction was built for testability and pays off here by accident. |
| Azure Functions HTTP API | Real work | The isolated-worker host, trigger attributes, and DI bootstrap are Azure-shaped. Either rewrite the handlers for Lambda, or containerise the whole host onto App Runner / Cloud Run — the latter keeps the code and gives up the serverless billing. |
| Managed Identity | Real work | Every secret-less credential flow re-expressed as IAM roles or Workload Identity. Mechanical, but it touches every service that reads a secret. |
| Key Vault references in app settings | Real work | Azure resolves @Microsoft.KeyVault(...) references at startup. Neither competitor has that exact feature; it becomes explicit lookup code. |
| Application Insights instrumentation | One seam | Re-target to OpenTelemetry, which both alternatives ingest. Arguably an improvement regardless of cloud. |
| Pulumi infrastructure definitions | One seam | The stack is rewritten against a different provider, but the tool, the language, and the workflow survive. Choosing Pulumi over ARM templates is what keeps this a rewrite rather than a re-learn. |
| Azure DevOps pipelines | Portable as-is | Azure DevOps deploys to AWS and Google perfectly well. No reason to move CI at all. |
Estimate the serious rows at a few focused weeks. Against a saving of roughly $500/year at Scenario A prices, the migration does not pay for itself on cost alone — and saying so is the point of doing the arithmetic. The same weeks spent moving the four static sites off a Windows plan and onto free static hosting would save more, on the cloud already in use, with no migration risk at all.
Related Reading
- Lean Cloud Economics — how the bill got this small in the first place, and the capacity ladder above it
- Blob Storage Architecture — the storage layer this page prices
- Infrastructure as Code — the Pulumi stacks that make the rewrite row above a bounded job
- Azure Architecture — what is actually deployed today