How to connect BigQuery to Google Sheets without pulling the warehouse in
Connect BigQuery to Google Sheets with Connected Sheets, a scheduled extract or an API pull. Pick one and control query costs.
On this page
- Key takeaways
- What we'll cover
- Three mechanisms, three purposes
- Aggregate in the warehouse
- Building it with CodeWords
- The cost of a shared sheet
- Row limits and what happens at them
- Types that do not survive the trip
- Keeping a scheduled extract honest
- Who can see the sheet, and who could not see the data
- Making it survive
- Limits worth knowing about
- What to set up first
- Frequently asked questions
- Related reading
To connect BigQuery to Google Sheets, first decide what the sheet is for, then pick the matching mechanism: Connected Sheets for a live slice someone explores, a scheduled extract for a report people read, or an ad hoc API pull for a one-off. Sending a whole table to the sheet slows it down and raises the BigQuery bill.
Key takeaways
- Use Connected Sheets when someone needs to change the slice, and a scheduled extract when people only read a report.
- Aggregate in SQL so the sheet receives dozens of rows, not thousands.
- BigQuery bills on bytes scanned, so select only the columns you need and filter on partitioned columns.
- Write the run time into the sheet, because a stale sheet looks the same as a current one.
- Sheet sharing is separate from warehouse permissions, so check who can open the sheet.
What we'll cover
- Three mechanisms, three purposes
- Aggregate in the warehouse
- Building it with CodeWords
- The cost of a shared sheet
- Row limits and what happens at them
- Types that do not survive the trip
- Keeping a scheduled extract honest
- Who can see the sheet, and who could not see the data
- Making it survive
- Limits worth knowing about
- What to set up first
- Frequently asked questions
Three mechanisms, three purposes
BigQuery data reaches a sheet through three mechanisms: Connected Sheets, a scheduled extract and an ad hoc API pull. Each suits a different purpose.
- Connected Sheets queries BigQuery from inside the spreadsheet, with pivots and refreshes, without the data living in the sheet. It suits an analyst exploring, and every refresh is a query someone pays for.
- A scheduled extract writes a result into a sheet on a schedule. It suits a report people read and a downstream process that reads the sheet. The cost is one predictable query per run.
- An ad hoc pull through the API suits a one-off. It is the mechanism most likely to keep running for two years after the one-off.
To choose, ask whether anybody needs to change the slice. If not, a scheduled extract is cheaper and faster to open, and it works when the viewer has no BigQuery access.
Aggregate in the warehouse
Aggregate in the warehouse by sending results to the sheet, not rows. The warehouse computes an answer far better than a spreadsheet formula over fifty thousand rows, and this one habit makes everything else manageable.
- Group, filter and limit in SQL. Every row you do not send is cheaper to query, faster to write and faster for the sheet to open.
- Pre-aggregate into a table if the same query runs often. A scheduled query that builds a small daily summary costs a fraction of querying the raw events each time.
- Resist "just give me everything and I'll filter it". That request leaves a sheet with two hundred thousand rows and a filter view nobody can load on a laptop.
- Ask what decision the sheet supports. Most answers need a few dozen rows.
Building it with CodeWords
CodeWords connects to 3,000+ integrations (CodeWords integrations directory, 2026), and you make each connection once and reuse it. You describe the outcome and Cody, the automation builder, builds, connects and deploys it.
- Open CodeWords and start a new automation.
- Describe to Cody what should happen in plain language: which query, how often, and which sheet it should land in.
- Authorize the connection with a service account that has read access to the relevant dataset and access to the target spreadsheet.
- Describe the exceptions: a query returning nothing, a result larger than expected, a schema change in the source table.
- Run it against a copy of the sheet and confirm the numbers against a period you already know.
The free plan covers light use. Pro costs $39 per month ($33 per month billed yearly) and Business costs $100 per month (CodeWords pricing page, 2026). Details are on the pricing page.
The cost of a shared sheet
A shared Connected Sheets report raises the BigQuery bill because every refresh is a query, and BigQuery bills for bytes scanned, not rows returned. The cost arrives as an invoice, not as an error.
- Refreshes multiply. A sheet shared with thirty people who each refresh on opening runs thirty queries.
- A
SELECT *on a wide table scans every column, even if the sheet shows twelve. Selecting only the columns you need is the largest single saving. - Partition and cluster filters reduce the scan. A query filtered on a partitioned date column scans far less than an unfiltered one.
- Scheduled extracts are predictable. They run one query per run, however many people open the sheet.
- Set a maximum bytes billed on anything a person can trigger, so a mistake fails instead of costing money.
- Report cost by query. If you cannot see which sheet is expensive, you cannot fix it. The usual culprit is one report nobody remembers creating.
Row limits and what happens at them
Google Sheets has a hard cell limit per spreadsheet, and a wide table reaches it sooner than people expect because columns multiply against rows. A write that exceeds the limit fails, often partway.
- A partial write leaves the sheet in a state nobody notices is incomplete.
- Truncation is worse than failure. A sheet quietly holding the first part of a result is a sheet someone will make a decision from.
- Check the row count before writing, and refuse with a clear message instead of attempting the write.
- If the answer needs that many rows, the destination is wrong. Point a reporting tool at the warehouse, or narrow the question.
Types that do not survive the trip
Five BigQuery data types change on their way into a sheet, and each produces a wrong number instead of an error.
- Timestamps carry a timezone in BigQuery and land in the sheet's own timezone, a workbook setting most people have never checked.
- Large integers lose precision. Sheets stores numbers as floating point, so large identifiers are rounded without warning. Write them as text.
- Numeric and decimal types round when they become spreadsheet numbers, which matters for anything financial.
- Nested and repeated fields have no spreadsheet equivalent. Flatten them deliberately in SQL.
- Nulls become empty cells, which spreadsheet formulas treat as zero, and that changes averages.
Keeping a scheduled extract honest
Keep a scheduled extract honest by showing when it ran and which query produced it. A stale sheet looks identical to a current one, and people quote it.
- Write the run time into the sheet, in a visible cell.
- Say which query produced the data, so a disputed number can be checked.
- Replace the range instead of appending, unless the sheet is deliberately a log, or duplicates accumulate.
- Report when the result is empty instead of writing an empty sheet. An empty sheet reads as "zero", not "the query broke".
- Alert on implausible magnitudes before writing. A report that silently halves is worse than one that fails.
Who can see the sheet, and who could not see the data
Spreadsheet sharing is independent of BigQuery permissions. A dataset restricted to six people becomes visible to everyone the sheet is shared with, and nothing warns you.
- Link sharing is the usual cause. A sheet set to "anyone with the link" carries whatever the extract put in it.
- Aggregate away the sensitivity. A summary by region is shareable in ways a row per customer is not, and it is usually what the reader wanted.
- Exclude columns nobody needs. Identifiers, email addresses and free-text fields arrive because they were in the table, not because someone asked.
- Check the sheet's sharing when you build the extract, and again if the report becomes important, since access widens over time.
- Note the retention difference. A deletion in the warehouse does not reach a spreadsheet copy, which matters for data under a retention policy.
Making it survive
Make the connection survive by writing idempotently, using a service account and capping query cost. Each step prevents one category of incident.
- Make writes idempotent, replacing a named range instead of appending.
- Handle schema changes in the source. A renamed column breaks the query, and a clear report beats a sheet with a missing column.
- Use a service account, not a person's credentials, or the report stops when they leave.
- Set a query timeout and a bytes-billed cap. Both are free to set.
- Report the outcome: rows written, bytes scanned and duration. Bytes scanned keeps the cost conversation grounded.
Limits worth knowing about
Five limits shape a BigQuery to Sheets connection.
- Sheets has a total cell limit per spreadsheet, which wide tables reach quickly.
- Sheets API writes are rate limited, so very large writes need chunking.
- Connected Sheets has its own result limits and does not replace a reporting tool on large data.
- BigQuery bills on bytes scanned, so the columns and partitions your query touches drive the cost.
- Query results have a size limit for direct retrieval. Above it, write to a destination table first.
What to set up first
Set up a scheduled extract of one small, aggregated result first, with the run time written into the sheet. Replace whichever report someone currently produces by hand, because that report already has a definition and an audience.
Two habits make the difference. Aggregate in SQL so the sheet receives dozens of rows, since almost every problem on this page follows from sending too much. And put the run time where people will see it, because a sheet nobody knows is three weeks old is worse than no sheet.
Frequently asked questions
Connected Sheets or a scheduled extract?
Use Connected Sheets when someone needs to change the slice and has warehouse access. Use a scheduled extract for a report people read. It costs one query per run however many people open it, and it works for viewers with no BigQuery access.
Why is our BigQuery bill rising?
The usual causes are a shared sheet refreshing for every viewer, a SELECT * on a wide table, or a query with no partition filter. BigQuery bills on bytes scanned, so the columns and partitions you touch matter more than the rows you return.
What happens when the result is too large?
The write fails, often partway, leaving a partial sheet that nobody notices is partial. Check the row count first and refuse with a clear message. If the answer needs that many rows, a spreadsheet is the wrong destination.
Why are large identifiers wrong in the sheet?
Google Sheets stores numbers as floating point and loses precision beyond a certain size. Write identifiers as text instead of numbers. This also stops the spreadsheet from reformatting them.
Why do timestamps look shifted?
BigQuery timestamps carry a timezone and land in the spreadsheet's own timezone, a workbook setting most people have never checked. State the timezone in the sheet so nobody has to guess which one applies.
Should the sheet append or replace?
Replace a named range, unless the sheet is deliberately a log. Appending accumulates duplicate rows on every retry, and retries happen more often than people expect.
How do I stop people quoting a stale sheet?
Write the run time into a visible cell on every run. A stale sheet looks exactly like a current one, and that is how a number from three weeks ago ends up in a board pack.
Does warehouse access control apply to the sheet?
No. Sheet sharing is separate from BigQuery permissions, so an extract from a restricted dataset becomes visible to everyone the spreadsheet is shared with. Check the sharing when you build the extract, and aggregate away anything that should not travel.
Does deleting data from the warehouse clear the sheet?
No. A spreadsheet is a separate copy, and no retention policy or deletion request in the warehouse reaches it. Remember this before an extract includes personal data.