Do you run workloads on more than one cloud? Then you have probably built a spreadsheet or a SQL script to line up AWS, Azure and Google Cloud bills. That script breaks whenever a provider renames a field. The FinOps Open Cost and Usage Specification (FOCUS) fixes this at the source. FinOps is the habit of engineering and finance teams managing cloud spending together. FOCUS is an open standard for billing data, and all three major providers can now export cost data in it.
This FOCUS billing data guide shows how to turn on those exports and query them side by side. A schema is simply the agreed list of column names and what each one means. At CloudSkill Consulting LLC, we treat a shared cost schema as the first step of any multi-cloud FinOps practice, before dashboards or optimization work.
Why one cost schema helps
Each cloud writes its bill in its own way. AWS, Azure and Google Cloud use different column names, different date fields and different words for the same idea. So when a finance team asks a simple question, like "how much did we spend on compute last month?", someone has to translate three files first. That work is slow, and it is easy to get wrong.
A shared schema removes the translation step. When every bill uses the same column names and the same meanings, one query can answer the question for all three clouds. This is the main idea of this post: agree on the shape of the data first, and the reports become much simpler to build and to trust.
Figure 1 shows this idea as a picture. On the left are the three bills, each with its own column names. In the middle is the FOCUS export, which uses the same column names in every cloud. On the right is the payoff: one query that works for all three.

Figure 1. Three bills with different column names become one FOCUS schema, so one query can answer for all three clouds.
What FOCUS standardizes
FOCUS defines common column names and meanings for cost and usage data (specification). A few you will use constantly:
| Column | Question it answers |
|---|---|
ProviderName |
Which cloud (or vendor) produced this charge? |
ServiceName |
Which service, in the provider's own naming? |
SubAccountId |
Which AWS account, Azure subscription or Google Cloud project? |
ChargePeriodStart |
When did the charge apply? |
ChargeCategory |
Is it usage, a purchase, tax, a credit or an adjustment? |
BilledCost |
What shows up on the invoice? |
EffectiveCost |
What did it really cost once discounts and prepaid commitments are spread across usage? |
Tags |
Which team, app or environment owns it? |
In plain words: SubAccountId tells you where the money went, ServiceName tells you what it was spent on, ChargePeriodStart tells you when, and Tags help you find who owns it. If you can answer those four questions for every row, you already have the base for showback reports.

Figure 2. Read each FOCUS row by asking four questions: where, what, when and who.
Three words come up a lot in FinOps, so here they are in plain words:
- Showback means showing each team what it spent. Nobody is charged; it is just a report.
- Chargeback means actually moving that cost to each team's own budget.
- Unit cost means cost per one unit of business work, for example cost per customer, per order or per 1,000 API calls.
Providers can add their own columns, but these must start with x_. AWS, for example, adds x_ServiceCode, x_UsageType and x_Operation. Keep these out of shared queries, and use them only when you're digging into a single provider.
Column names here follow FOCUS 1.0. AWS now also offers a FOCUS 1.2 table, and newer versions add columns and change some values. Check which version each export uses before you hard-code any names.
Turning on the export in each cloud
AWS: in Billing and Cost Management, create a Data Export and choose the FOCUS 1.0 with AWS columns table (a FOCUS 1.2 table is also offered; try to keep one version across all three clouds). It lands in S3, Amazon's file storage service (create a data export, column dictionary).
Azure: in Cost Management, create an export with the Cost and usage details (FOCUS) dataset. It writes to a storage account (exports tutorial, FOCUS schema).
Google Cloud: on the Billing export page, choose Enable FOCUS export. Google creates a read-only (Google calls it "immutable") linked BigQuery dataset named gcp_billing_immutable_<BILLING_ACCOUNT_ID>_<LOCATION>, with a table named gcp_billing_export_focus_<BILLING_ACCOUNT_ID> (setup, schema). This export is in Preview, which Google covers under its "Pre-GA Offerings Terms", so it may have limited support. Google's docs recommend querying through a view, so schema changes don't break your queries. That's good advice for all three clouds.
Before you turn on any export, pick one place to store the data. Most teams use the data warehouse they already run, such as BigQuery, Amazon Athena or Azure Synapse. Then give each export its own table, and give read access only to the people and tools that need it. Billing data can show account names and tags, so treat it as internal data.
Each export also takes time to fill. New exports often start with the current month, and some providers let you request older months. Check each provider's documentation linked above for what history is available.
Figure 3 sums up this section. Each cloud has its own switch for the FOCUS export, and each one writes to its own storage: S3 for AWS, a storage account for Azure, and a linked BigQuery dataset for Google Cloud. From there, all three land in your one data warehouse.

Figure 3. Where each cloud's FOCUS export is turned on, and where its data lands before it reaches your warehouse.
One view over three exports
After you load the AWS and Azure files into the same warehouse as the Google Cloud table, a thin view is enough. It picks only the columns you share across clouds:
CREATE OR REPLACE VIEW finops.focus_all AS
SELECT ProviderName, ServiceName, SubAccountId, ChargePeriodStart,
ChargeCategory, BillingCurrency, BilledCost, EffectiveCost
FROM finops.aws_focus
UNION ALL
SELECT ProviderName, ServiceName, SubAccountId, ChargePeriodStart,
ChargeCategory, BillingCurrency, BilledCost, EffectiveCost
FROM finops.azure_focus
UNION ALL
SELECT ProviderName, ServiceName, SubAccountId, ChargePeriodStart,
ChargeCategory, BillingCurrency, BilledCost, EffectiveCost
FROM finops.gcp_focus;
Naming every column, instead of using SELECT *, keeps the view stable when a provider adds new x_ columns.

Figure 4. The three export tables are joined with UNION ALL into one view, finops.focus_all, and every report starts from that view.
A first question to ask the view: monthly usage cost per cloud.
SELECT ProviderName,
DATE_TRUNC(DATE(ChargePeriodStart), MONTH) AS month,
BillingCurrency,
SUM(EffectiveCost) AS effective_cost
FROM finops.focus_all
WHERE ChargeCategory = 'Usage'
GROUP BY 1, 2, 3
ORDER BY 2, 1;
(Date functions differ by warehouse. This example uses BigQuery syntax.)
When you add a new report, start from this view instead of the raw tables. That way, if one provider changes its export, you fix the view once and every report keeps working.
BilledCost or EffectiveCost?
They answer different questions, so choose one per report and label it:
- BilledCost matches invoices. Use it when you reconcile with finance.
- EffectiveCost spreads commitment purchases and discounts across the usage they cover. Use it for showback, unit costs and trends.
Never add the two together. Read the spec's definition of each before you build chargeback on top of either one.
Here is a simple way to think about it. Say you pay up front for a one-year commitment. BilledCost shows that payment in the month you paid it. EffectiveCost spreads the same amount over the usage it covers during the year. Both numbers are correct, but they tell different stories, so a report that mixes them will confuse readers.

Figure 5. The same one-year commitment seen two ways: BilledCost puts it all in the month you paid, EffectiveCost spreads it across the year.
Before you trust the numbers
- [ ] Each export covers the same date range, and the latest days have been refreshed (all three providers can revise recent data).
- [ ] Currencies are grouped or converted. Don't sum
BillingCurrencyvalues that differ. - [ ] Tag keys mean the same thing in every cloud (
teamvsTeamvsowner). - [ ] Credits and tax rows are included or excluded on purpose.
- [ ] Shared queries use no
x_columns.
A simple first-week plan
If you are new to FOCUS, keep the first week small:
- Turn on the FOCUS export in one cloud and wait for the first data to land.
- Load it into your warehouse and run the monthly cost query above for that one cloud.
- Compare the result with the cost tool in that cloud's console. Small gaps can come from timing, credits or currency, so write down the reason for any gap you find.
- Add the second and third cloud only after the first one matches.
Going one cloud at a time makes problems easy to find. If you add all three at once and the totals look wrong, it is hard to tell which export caused it.
A single schema doesn't cut costs on its own. What it does is let you ask "what does this cost us?" once, instead of three times in three formats.
Written by the CloudSkill Consulting LLC team, a multi-cloud architecture and FinOps consultancy (cloudskillconsulting.com). Billing data is where a lot of our client work begins. Problems like this one fill a normal week for our team, so anyone weighing CloudSkill Consulting LLC careers can expect to work on them. Questions on this guide: info@cloudskillconsulting.com
Top comments (0)