GMI · TECHNOLOGY OBSERVATORY // ALL SYSTEMS NOMINAL
ENGINEERED BY LEOPARD DATA

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.

THE SAME SYSTEM, THREE WAYS
rendering diagram…
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 --- C5
Five workloads, mapped to each cloud's native service. The shapes are identical because the architecture is deliberately portable: MySQL rather than a proprietary datastore, static front-ends rather than a server-rendered app tier, and one batch VM rather than a managed scheduler.

How 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.

AssumptionValueWhy
Pricing date27 August 2026All three rate cards read the same day
RegionsAzure Central US · AWS us-east-2 (Ohio) · GCP us-central1 (Iowa)Geographically comparable Midwest regions, all three vendors' low-cost tier
Month730 hoursThe convention all three vendors use
DiscountsNone appliedList 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 tiersApplied only where permanentCloudFront's 1 TB / 10M requests and Google's 50 GiB of logs are standing allowances, not 12-month trials, so they count
EgressExcludedReal 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.

LayerAzure (in use)AWS equivalentGoogle Cloud equivalent
Compute & hosting
Static site hosting in useApp Service (Windows B1) — Static Web Apps would fitS3 + CloudFront, or Amplify HostingCloud Storage + Cloud CDN, or Firebase Hosting
Serverless API in useAzure Functions (isolated worker)Lambda + API Gateway (HTTP API)Cloud Run functions
Container / PaaS hostApp Service (Linux)App Runner, or Elastic BeanstalkCloud Run, or App Engine
Batch VM in useVirtual Machines (B-series burstable)EC2 (t3 / t4g Graviton)Compute Engine (e2)
Data
Managed MySQL in useAzure Database for MySQL — Flexible ServerRDS for MySQL, or Aurora MySQLCloud SQL for MySQL
Object storage in useBlob Storage (ZRS + LRS)S3 (Standard / One Zone-IA)Cloud Storage (Standard / Nearline)
Block storage in useManaged Disks (Premium SSD P4)EBS (gp3)Persistent Disk (balanced)
Job queue in useMySQL table — no queue product rentedSQSPub/Sub
Security & identity
Secret storage in useKey VaultSecrets Manager, or SSM Parameter StoreSecret Manager
Workload identity in useManaged IdentityIAM roles (instance profiles)Service accounts / Workload Identity
Private networking in useVirtual Network + NSGVPC + security groupsVPC + firewall rules
TLS certificates in useApp Service managed certificatesAWS Certificate ManagerGoogle-managed SSL certificates
Delivery & operations
CDNFront Door / Azure CDNCloudFrontCloud CDN
DNSAzure DNSRoute 53Cloud DNS
APM / tracing in useApplication InsightsCloudWatch + X-RayCloud Monitoring + Cloud Trace
Log aggregation in useLog AnalyticsCloudWatch LogsCloud Logging
CI/CD in useAzure DevOps PipelinesCodePipeline + CodeBuildCloud Build
Infrastructure as code in usePulumi (Azure Native provider)Pulumi (AWS provider), or CloudFormationPulumi (GCP provider), or Config Controller
Container registryAzure Container RegistryElastic Container RegistryArtifact Registry
Intelligence & messaging
Forecasting in useML.NET, in-process — no ML service rentedSageMakerVertex AI
LLM analysis in useAnthropic API directBedrockVertex AI
Transactional email in useSendGridSESNo first-party service
SMS in useTwilioSNS / End User MessagingNo 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.

WorkloadAzure — todayAWSGoogle 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.

WorkloadAzureAWSGoogle 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:

ComponentPortabilityWhat it would take
Blazor WebAssembly front-endsPortable as-isStatic output. Copy the files to a bucket. Genuinely zero work.
MySQL schema and dataPortable as-isA dump and a restore. Same engine, same version, all three clouds.
Background console servicesPortable as-isPlain .NET processes under systemd on a Linux VM. The VM changes name; nothing else does.
Blob storage accessOne seamAll 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 APIReal workThe 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 IdentityReal workEvery 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 settingsReal workAzure resolves @Microsoft.KeyVault(...) references at startup. Neither competitor has that exact feature; it becomes explicit lookup code.
Application Insights instrumentationOne seamRe-target to OpenTelemetry, which both alternatives ingest. Arguably an improvement regardless of cloud.
Pulumi infrastructure definitionsOne seamThe 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 pipelinesPortable as-isAzure 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