How to use the aws, azure and gcp hubs together to estimate a migration
The method the three cuppy hubs exist to support. Six phases from inventory to a defensible number, the eight measurements an estimate is not valid without, the five difference classes every parity guide reports, the three costs no vendor calculator contains, and an explicit statement of what this method cannot do.
markdownguidev1PMVR-NGH4stage: designtrust: officialfamily: overviewservice: migration-centerinterface: anymigration estimateparitycross-cloudaws hubazure hubgcp hubnamingquota modelpricing dimensionregional modelIAM modelegresswavesright-sizingcorrectness risk
Using the three hubs for one estimate
cuppy serves three vendor hubs — aws, azure and gcp — and each is written to the same
shape: a reference per service, an error catalogue per family, guides per intent. This hub adds one thing the
other two do not yet have: a parity guide per family, whose job is not to list counterpart names but to
list the documented differences that change an estimate.
This document is the method those guides serve.
Phase 0 — decide what question you are answering
Three different questions get called "a migration estimate", and they need different work:
| Question | What it needs |
|---|---|
| "roughly, what would this cost over there?" | phases 1 and 4. Hours |
| "what would it cost, and what would we have to change?" | phases 1 to 4. Days |
| "commit to a number and a date" | all six phases, plus one wave actually executed. Weeks |
Answering the third with the first one's work is the most common failure, and it is not a technical one.
Phase 1 — inventory and measure
Use the destination cloud's own assessment tool — on Google Cloud, Migration Center, which explicitly covers "on-premises or other cloud environments". Run it once per candidate destination: the inventory is the same, the pricing and the technical-fit analysis are the target's own, and two runs is how you compare two destinations honestly.
The eight measurements, each with the estimate line it feeds:
| # | Measure | Feeds |
|---|---|---|
| 1 | utilisation, not provisioned capacity | right-sizing — usually the largest saving available |
| 2 | network dependencies between systems | the wave boundaries |
| 3 | bytes to move, by dataset | egress, and the transfer window |
| 4 | identities, keys and secrets per workload | the identity line, and the keys you can delete |
| 5 | logs GB/day, metric count and label cardinality, trace volume | the observability line |
| 6 | count of dashboards and alerting policies | effort — they are re-created, never migrated |
| 7 | permissions each workload actually used | the role-mapping work |
| 8 | request/query profile (bytes scanned, RU/s, average message size, requests per second) | every service whose billing dimension differs from the source's |
An estimate missing #1, #2 or #3 is not an estimate. Full detail and the failure mode of skipping each:
guides/migration/assess-before-you-move.md.
Phase 2 — map the names, then stop trusting the map
Open the parity guide for each family in scope — guides/parity/identity.md, .../iac.md, .../storage.md,
.../compute.md, .../networking.md, .../databases.md, .../messaging.md, .../data.md,
.../observability.md, .../migration.md — and take §1 of each, the name table.
Three rules, each learned from a published table being misleading rather than wrong:
- Prefer a product page to a mapping table. Microsoft's table pairs Cloud Deployment Manager with Azure
Resource Manager; Deployment Manager reached end of support on 31 March 2026. Google's own table is dated December 2024.
- A one-to-many row is a finding, not a formatting problem. Microsoft maps Pub/Sub to three Azure
services and Spanner to two. One-to-many means the source product's jobs are divided on the target, and the division is per topic, per database, per workload — triage work that belongs in the estimate.
- A name match is not a capability match. Both tables map Bigtable to Azure Table Storage. Treat
every row as a starting point for phase 3, never as a conclusion.
Phase 3 — price the differences, in five classes
Every parity guide in this hub reports the same five classes, because these are the five that move a number:
| Class | What to look for | Worked example from this hub |
|---|---|---|
| naming | a renamed or retired product | Deployment Manager is out of support; "Cloud Functions" is now Cloud Run functions; the Dataproc overview is now titled Managed Service for Apache Spark |
| quota and limit model | what is fixed against what is askable | AWS publishes an auto-approved increase table; Google Cloud and Azure publish fixed identity ceilings. A design that leans on raising a limit works on one cloud and not the others |
| pricing dimension | the unit, never the price | BigQuery on-demand bills bytes scanned; Redshift bills node-hours. Pub/Sub bills bytes; SQS bills requests. Neither converts without #8 |
| regional model | what is global, regional, zonal | a Google Cloud VPC is global; an AWS VPC and an Azure VNet are regional. N networks become one, and the transit object disappears |
| IAM model | how a grant is expressed and bounded | AWS policy JSON decomposes into a Google Cloud binding + condition + deny policy + PAB policy. Budget per policy document, not per role |
And one class that is not a cost at all, which this hub reports anyway because it is worse than a cost:
Correctness risk. AWS Lambda runs one request per execution environment; Cloud Run functions run up to 1000 concurrent requests per instance. Code that was safe under the first assumption races under the second. A migration that treats this as a performance tuning note ships a bug. Also: adding a second Bigtable cluster silently changes the instance from strongly to eventually consistent.
Write these out per workload. This list — not the cost table — is the migration's actual scope.
Phase 4 — the three costs no calculator contains
- Source-side egress. Billed by the cloud you are leaving. Absent from the destination's calculator. On a
large estate it can exceed a year of the destination's storage bill. Size it from #3, and note that event-driven mirroring means it is charged over the whole migration window.
- The work in phase 3. Policy decomposition, schema conversion, re-instrumentation, dashboard
re-creation, consumer idempotency. All of it is labour, none of it is on a price list.
- The destination's own commitments. Minimum storage durations start on arrival — Cloud Storage
ARCHIVE commits 365 days, against 180 on the other two clouds. Landing a migration straight into a
cold class starts that clock on data you have not validated yet.
Phase 5 — sequence from the dependency graph, not from the org chart
Waves come from measurement #2. Two systems that talk to each other move together, or their traffic crosses clouds at egress rates for as long as the wave gap lasts.
Then pre-flight each wave: destination quotas, per project and per region, requested in advance. A wave
that fails half-done leaves the source drained and the target incomplete, which is the worst available state
(reference/migration/errors.md §3).
Phase 6 — execute one wave, then re-estimate
Pick the smallest wave with a real dependency in it. Execute it. Then re-run phase 1 against the result.
One executed wave replaces more assumptions than any amount of further analysis, and it converts the estimate from a model into a measurement. If a number has to be committed, commit it after this phase and not before.
What this method cannot do
- It cannot tell you whether a predefined role grants the same operations as its counterpart. No published
table claims it does. Measurement #7 is the only honest route.
- It cannot tell you whether your SQL, your stored procedures or your dialect port. That is assessment
work, per schema.
- It cannot tell you whether the application behaves the same afterwards. The observability baseline
(#5, #6) is what makes that a measurable question instead of an argument.
- It cannot decide whether to migrate. This hub documents and never acts: it narrows the unknowns in the
decision and takes no part in it.
Keeping the three hubs honest
Every claim in a parity guide cites a page with a read date, and the hub states absences explicitly —
"the page does not say" is written out rather than filled in from memory. When a vendor page has moved on,
file a drift report: guides/when-the-docs-have-changed.md.