Register your interest: Tag @Cody, get an agent
BlogEngineering

How to connect Snowflake to Google Sheets and control what it costs

A warehouse that bills by the second rewards batching and punishes per-viewer refreshes. Warehouse sizing, auto-suspend, network policies, and getting credentials into a scheduled job.

Osman RamadanOsman Ramadan11 min read

Summarize with AI

How to connect Snowflake to Google Sheets and control what it costs
On this page

Snowflake charges for compute time rather than for data scanned, which changes the arithmetic of feeding a spreadsheet. A query that takes eight seconds on an extra-small warehouse is nearly free; the same query triggered forty times a day by people opening a sheet is not, mostly because of what happens between the queries.

The details that decide the bill are warehouse size, auto-suspend, and how often something wakes the warehouse up. None of them is about SQL, which is why they get overlooked.

What we'll cover

Compute time, not bytes

Credits accrue while a warehouse is running, billed in fine increments with a minimum charge each time it starts.

A larger warehouse costs proportionally more per second and finishes proportionally faster, so for a query that is genuinely parallelisable the total can be similar — and for a small report it is simply more expensive.

Idle time is charged until the warehouse suspends, which is where most avoidable cost sits.

Results are cached. An identical query against unchanged data can return from cache without running the warehouse at all, which makes repeated identical reads almost free and makes small query variations surprisingly expensive.

Batch rather than trickle. One scheduled query that does everything beats twelve that each wake the warehouse, because the wake-ups are the cost.

Auto-suspend and the wake-up cost

The setting that determines whether a reporting workload is cheap or not.

Auto-suspend set long keeps the warehouse warm — good for a stream of queries, wasteful for a report that runs twice a day.

Auto-suspend set short saves idle time and means each run pays the start-up minimum.

A dedicated warehouse for reporting is usually the right answer: small, short auto-suspend, and separate from anything interactive so a heavy report does not affect an analyst mid-query.

Cluster your schedules. If several reports run each morning, running them within the same window means one wake-up rather than five.

Watch for the trickle pattern. A sheet refreshing on open, from a handful of people through the day, keeps a warehouse alive almost continuously for a few dozen seconds of actual work.

Building it with CodeWords

CodeWords connects to more than 3,000 integrations, and the connection is made once and reused.

  1. Open CodeWords and start a new automation.
  2. Describe what should happen in plain language to Cody, the automation builder: which query, on which warehouse, how often, and which sheet it lands in.
  3. Authorize the connection with a dedicated Snowflake user using key pair authentication, restricted to a reporting role and warehouse, plus access to the target spreadsheet.
  4. Describe the exceptions: a query returning nothing, a result larger than the sheet can hold, a warehouse that is suspended and slow to resume.
  5. Run it against a copy of the sheet and confirm the figures for a period you already know.

You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.

Warehouse sizing for a report

Start at the smallest size. Most reporting queries against modelled tables do not benefit from more, and the instinct to size up is usually solving a modelling problem with money.

Size up only with evidence. If the query spills to disk or queues, that is a reason; slow because it scans a badly clustered table is not.

Separate reporting from transformation. A warehouse shared with your transformation jobs means a report competes with a nightly build, and both look intermittently slow.

Set a resource monitor on the reporting warehouse, so a runaway job has a ceiling rather than a surprise.

Query the account usage views for credits by warehouse and by query. This is where a single expensive report becomes visible, and nobody looks unless something is automated to tell them.

Getting credentials into a scheduled job

Worth doing properly, since this is the step most often done badly.

Use key pair authentication for anything unattended, rather than a password.

Create a dedicated user for the integration, not a person's account, so it survives them leaving and its activity is attributable.

Grant a role with select on the specific views it reads, plus usage on one warehouse. Reporting needs nothing more.

Rotate keys on a schedule, and confirm the next scheduled run succeeded, since a rotation that silently breaks a Monday report is discovered on Wednesday.

Never let the report's role own objects, so a mistake cannot drop anything.

Network policies, which block you first

The thing that stops the project before any of the above matters.

Network policies restrict which addresses may connect, and many organisations have one.

Confirm what your automation egresses from before asking for an allowlist entry, because that is the detail the request hinges on.

Private connectivity is available and is a larger piece of work, so establish early whether it is required.

Test the connection before building the query. A failed connection at the end of a build is the same problem discovered later, and the conversation with whoever owns the policy takes longer than the code.

Expect authentication and network errors to look similar from the outside, so log enough to tell them apart.

Making the extract trustworthy

Write the run time into the sheet, visibly, since a stale sheet looks identical to a current one.

Name the query or the model that produced it, so a disputed number can be traced.

Replace a named range rather than appending, unless the sheet is deliberately a log.

Report an empty result rather than writing an empty sheet, because an empty sheet reads as zero.

Flag implausible magnitudes before writing, since a silently halved figure is worse than a failure.

Reading from a model, not a raw table

Where the extract points determines how often it breaks.

Point at a view or a modelled table, not at raw ingested data. Raw tables change shape when a source system changes, and your spreadsheet is the last thing anybody thinks about when that happens.

Let the modelling layer own the definitions. If "active customer" is defined in a view, every report agrees; if it is defined in each extract's SQL, they diverge and somebody spends a morning working out which is right.

Ask for a view if one does not exist. A reporting view built for the purpose is a small request and it makes the extract stable.

Avoid SQL that reimplements business logic. An extract containing a hundred lines of case statements is a model nobody reviews, sitting outside the place models are reviewed.

Version the query with your other code, so a change to the definition has an author and a diff.

Say which model the sheet came from, in the sheet, so a disputed number leads back to a definition rather than to an argument.

Making it survive

Use a query timeout and a statement timeout on the role, both of which are free and prevent a runaway holding a warehouse open.

Handle the resume delay. A suspended warehouse takes a moment to start, and a short client timeout will treat that as a failure.

Make writes idempotent by replacing a range rather than appending.

Handle schema changes in the source view, reporting clearly rather than writing a sheet with a missing column.

Report the outcome. Rows written, execution time, and the warehouse used — the second and third are what keep the cost conversation grounded.

Limits worth knowing about

Sheets has a total cell limit, which wide results reach faster than people expect.

Sheets API writes are rate limited, so large writes need chunking.

Result caching depends on the query being identical and the underlying data unchanged, so a query with a timestamp in it never hits cache.

Minimum billing per warehouse start means very frequent small queries are disproportionately expensive.

Account usage views have a latency, so credit figures are not real-time and a cost report is retrospective.

What to set up first

Credit consumption reporting by warehouse and by query, delivered weekly. It is read-only, it runs on the smallest warehouse, and it is the thing that turns an unexplained bill into a named report somebody can decide about.

Two habits make the difference. Report the change week on week rather than the total, since a new expensive query is what you want to catch. And include the warehouse each query ran on, because a report competing with transformation jobs is a different fix from a report that is simply expensive.

Frequently asked questions

Why is our Snowflake bill higher than the query time suggests?

Idle time and wake-ups. Credits accrue while a warehouse runs, with a minimum charge each start, so a trickle of small queries through the day keeps a warehouse alive for far longer than the work takes.

Should I use a bigger warehouse for reporting?

Start at the smallest and size up only with evidence of spilling or queuing. A report that is slow because of how the data is modelled will not get meaningfully faster on a larger warehouse, and it will cost more.

What auto-suspend setting should a reporting warehouse have?

Short, on a warehouse dedicated to reporting, with the schedules clustered so several reports share one wake-up. Long auto-suspend suits interactive work and wastes credits on a twice-daily report.

How should credentials be handled?

Key pair authentication on a dedicated user with a reporting role granted select on specific views and usage on one warehouse. Never a person's account, and never a role that owns objects.

Why can the automation not connect at all?

Very often a network policy. Confirm which addresses your automation egresses from and get them allowlisted, and establish early whether private connectivity is required — that conversation takes longer than the build.

Why does the first query of the day take so long?

The warehouse was suspended and is resuming. It is the mechanism that saves you money the rest of the time. Allow for it in the client timeout rather than treating it as a failure.

How do I stop the same report being run repeatedly?

Schedule it once and have people read the sheet, rather than letting each viewer trigger a refresh. That single change converts a per-viewer cost into a fixed one and is usually the largest saving available.

Should the extract query raw tables?

No — point it at a view or a modelled table. Raw tables change shape when a source system changes, and business logic living inside an extract is a model that sits outside the place models get reviewed.

Two reports disagree about the same metric — why?

Almost always because each defines the metric in its own SQL. Move the definition into a view that both read, and name the view in the sheet so a dispute leads to a definition rather than an argument.

Get started today

Your first workflow is free to build.

Describe what you need. Cody handles the build, the connections, and the deployment.