This comparison is for a data engineer who has to bring a vendor's company data into a data warehouse and is choosing between Snowflake and BigQuery, or runs one and wants to know what would differ on the other. It covers the four things that differ in practice for an external feed: how files are loaded, how JSON is held, how shared data arrives and how each platform charges. Prices are left out, because each vendor publishes its own and they change. What follows is the model each one documents, checked on 4 October 2026.
Fokals is delivered direct, by REST API and as bulk files, which you load with the platform's own loader: COPY INTO on Snowflake and a load job on BigQuery. The examples use Hiring Activity from the hiring dataset: the open, new and closed postings of each company. The data dictionary gives its shape: CSV in UTF-8 with one header row, one row per company and closed UTC day, and the open postings by job function as a JSON object in a single cell. The same export can be taken as JSON Lines or as JSON.
The two side by side
| Snowflake | BigQuery | |
|---|---|---|
| Files load from | An internal stage, or an external stage over Amazon S3, Google Cloud Storage or Microsoft Azure | Cloud Storage or a local file, and Amazon S3 or Azure Blob Storage through a connection |
| Load command | COPY INTO an existing table | A load job: LOAD DATA in SQL, bq load, the console or the API |
| File formats | CSV, JSON, Avro, ORC, Parquet, XML | Avro, CSV, newline-delimited JSON, ORC, Parquet, and Datastore and Firestore exports |
| Compute for a batch load | A virtual warehouse you size, billed in credits | A shared pool of slots at no charge by default, or your own reservation |
| JSON column | VARIANT | JSON |
| Reading a key | column:key::number | LAX_INT64(column.key) |
| Shared data arrives as | A read-only database created from a share | A read-only linked dataset in your project |
| Query compute is charged by | The time a warehouse runs, in credits | The bytes each query processes, or slot capacity over time |
| Storage is charged by | A flat rate per terabyte on average daily bytes | Active and long-term rates, on logical or physical bytes |
Loading the file
On Snowflake a file waits in a stage, as its loading overview describes: an internal stage inside Snowflake, or an external stage over your own storage in Amazon S3, Google Cloud Storage or Microsoft Azure, regardless of the cloud that hosts the account. COPY INTO loads staged files into a table that already exists, on a virtual warehouse you choose. It skips files it has already loaded unless you set FORCE.
-- Snowflake: load by header name from a stage, the JSON cell kept as text for now
-- (stage and table names are illustrative)
copy into hiring_daily_landing
from @landing/hiring_daily/2026-10-03/
file_format = (
type = csv
parse_header = true
field_optionally_enclosed_by = '"'
error_on_column_count_mismatch = false
)
match_by_column_name = case_insensitive;BigQuery's introduction to loading lists batch loads, streaming loads, change data capture and federation to external data sources. A batch load reads from Cloud Storage or a local file, and the same page names the BigQuery Data Transfer Service for setting up recurring loads from Cloud Storage. It also says that a load job is atomic: either all records are inserted or none are. The LOAD DATA statement does the same from SQL, and loading CSV data shows that it can create a table, append to one or overwrite one.
-- BigQuery: create the table on the first run and append after, matching columns to the header
-- (dataset and bucket names are illustrative)
load data into company_data.hiring_daily (
company_id string,
isin string,
day date,
open_postings int64,
new_postings int64,
closed_postings int64,
by_function json
)
partition by day
from files (
format = 'CSV',
uris = ['gs://your-bucket/fokals/hiring_daily/2026-10-03/*.csv'],
skip_leading_rows = 1,
source_column_match = 'NAME',
ignore_unknown_values = true
);Three details decide whether these loads keep working.
- Matching by name. Both statements match columns to the header row, so a file whose columns arrive in a new order still loads. On BigQuery that is the option to match source columns by name, which reads the names from the last skipped row, as the CSV loading page says, and the option to ignore unknown values lets the file carry columns the table does not name. Both are set in the statement above.
- The JSON cell. Google's page on JSON data says a JSON column can be loaded from CSV and that quotes inside the cell must be escaped by doubling them. Open a sample file and check. If the cell does not load as
JSON, load it asSTRINGand convert it withSAFE.PARSE_JSON, which returnsNULLwhere the text does not parse. - Loading twice.
LOAD DATA INTOappends, so give each run a path of its own and load each path once. Daily Fokals rows are written once and never revised, so on either platform a merge keyed on the company ID and the day that inserts only new keys can be run again without harm.
The full pipelines, with a merge for daily increments, are in loading company data into Snowflake and loading company data into BigQuery.
JSON
Snowflake's semi-structured types are VARIANT, OBJECT and ARRAY. A VARIANT holds a value of any other type, loaded JSON is converted to an internal format built on these types, and a query walks it with a colon and dots and casts with ::.
BigQuery has a JSON type. Google's page says it lets you load semi-structured JSON without giving a schema first, and that BigQuery encodes and processes each field of the value individually. A query reads a field with a dot, an array element with a subscript, and converts with functions such as JSON_VALUE, INT64 and LAX_INT64. Field names are case-sensitive on both platforms.
-- Snowflake, by_function held as VARIANT
select company_id, day, by_function:sales::number as open_sales_postings
from company_hiring_daily
where day = date '2026-10-03';
-- BigQuery, by_function held as JSON
select company_id, day, lax_int64(by_function.sales) as open_sales_postings
from company_data.hiring_daily
where day = date '2026-10-03';The same page sets limits that shape a model on BigQuery. A table cannot be partitioned or clustered on a JSON column. Equality and comparison are not defined for the type, so a JSON value cannot be used directly in GROUP BY or ORDER BY and has to be extracted first. Row-level access policies cannot be applied to JSON columns. The practical rule is the same on both platforms: keep the cell whole, and pull the keys people filter and group on into plain typed columns.
Shared data
Some vendors deliver through a share and not through files, so it is worth knowing what would arrive. Snowflake's Secure Data Sharing gives the consumer a read-only database created from a share. Its documentation says that no data is copied, that the consumer pays only for the compute used to query, and that a direct share reaches accounts in the same region while a listing reaches other regions and clouds.
Google now calls its service BigQuery sharing, formerly Analytics Hub. A publisher places listings in a data exchange, which is private by default, and subscribing creates a linked dataset in your project: a read-only pointer to the shared dataset, with no data replicated. Google's documentation lists data storage as the publisher's cost and queries run against the shared data as the subscriber's. One documented control matters to a licensing team. A publisher can restrict data egress, and then copying, exporting and CREATE TABLE AS SELECT are unavailable on the linked dataset.
Fokals data takes the file route described above. It is delivered direct, by REST API and as bulk files, and loaded with the platform's own loader, so the tables are your own copy to partition, join and keep under your licence. The two marketplaces built on these mechanisms are compared in BigQuery Analytics Hub vs Snowflake Marketplace.
Pricing models
Snowflake's cost overview divides cost into compute, storage and data transfer. Compute consumes credits. A virtual warehouse is billed per second, with a minimum each time it starts. Serverless features such as Snowpipe run on compute that Snowflake manages. The cloud services layer is charged only when its daily use exceeds a share of daily warehouse use. Storage is a flat rate per terabyte on the average bytes stored each day. Bringing data in carries no fee, and moving it out to another region or cloud does. The cost overview holds the current figures.
BigQuery's pages on estimating and controlling costs and on editions describe two compute models, and its pricing page holds the current rates. On-demand charges for the bytes each query processes. Capacity charges for slots over time, under the three editions that the editions page lists, with autoscaling or commitments. Storage has an active rate and a long-term rate, which applies to a table or partition that has gone unmodified for the period the costs page states, and it can be billed on logical or physical bytes. Batch loading from Cloud Storage or a local file is not charged by default, because it runs on a shared pool of slots, and the batch loading page says Google does not guarantee that pool's capacity.
For a daily vendor feed the two models pull in different directions.
| Snowflake | BigQuery on-demand | |
|---|---|---|
| What the load costs | The time the warehouse runs | Nothing by default, then storage |
| What a query costs | The time the warehouse runs | The bytes it reads, which LIMIT does not reduce on a table that is not clustered |
| What to do about it | Run the day's loads together, so the warehouse starts once | Partition by day, filter on it, and select only the columns you need |
| What old data costs | The same flat storage rate | The long-term rate, once a partition has gone unmodified for the period Google states |
The last row has a consequence for this kind of data. Fokals writes each daily and weekly dataset once, after the period closes, and never revises it, so a table partitioned by day that you only append to leaves every past partition untouched, and each one passes to the long-term rate without any work on your side.
Which fits, by use
- Your analytics are on Google Cloud. BigQuery loads from Cloud Storage, and the default batch load is not charged.
- The vendor's files sit in Amazon S3 or Azure storage. A Snowflake external stage reads all three clouds' storage directly. BigQuery's
LOAD DATAdocuments loads from Amazon S3 and Azure Blob Storage through a connection, into a BigQuery region in the same location. - You want spend to follow capacity. Snowflake bills warehouse time. BigQuery offers the same idea as capacity pricing.
- You want spend to follow use. BigQuery on-demand bills each query for the bytes it reads, which rewards partitioned tables and narrow queries.
- Other vendors share on one of them. That platform saves a load for those datasets. Snowflake vs Databricks sets Snowflake against a lakehouse on the same questions.
Frequently asked questions
How do Snowflake and BigQuery charge for loading data?
Snowflake charges no fee for bringing data in, and a bulk load consumes credits on the virtual warehouse that runs COPY INTO, billed per second with a minimum each time the warehouse starts. BigQuery's batch loading page says there is no charge for batch loading from Cloud Storage or a local file using the shared pool of slots. On both, the loaded data is then charged as storage.
Can BigQuery load JSON Lines files?
Yes. BigQuery loads newline-delimited JSON from Cloud Storage or a local file, and its documentation says that format is the same as JSON Lines, with each object on its own line. A field declared as JSON type is loaded with the raw JSON value. Google notes that gzip-compressed JSON cannot be read in parallel, so it loads more slowly than uncompressed files.
What is the difference between VARIANT in Snowflake and JSON in BigQuery?
Both hold a JSON value in one column without a fixed schema. Snowflake's VARIANT can hold a value of any type and is read with a colon path and a double-colon cast. BigQuery's JSON type is read with a dot and converted with functions such as JSON_VALUE or LAX_INT64. BigQuery documents that a table cannot be partitioned or clustered on a JSON column and that JSON values cannot be grouped or ordered directly.
Is Analytics Hub now called BigQuery sharing?
Yes. Google's documentation names the service BigQuery sharing, formerly Analytics Hub, and its IAM roles keep the Analytics Hub name. A publisher places listings in a data exchange, and a subscriber receives a linked dataset in its own project, a read-only reference to the shared data with nothing replicated.
How do I load Fokals data into Snowflake or BigQuery?
Fokals is delivered direct, by REST API and as bulk files in CSV, JSON or JSON Lines, which you load with the platform's own loader: COPY INTO from a stage on Snowflake, a load job from Cloud Storage on BigQuery, as this comparison shows. Daily and weekly datasets are written once, after the period closes, and never revised, so each load only adds rows and past partitions stay untouched. The tables are your own copy, held under your licence.
The queries and code on this page are examples to adapt. Test them in your own environment before you rely on them.
What this page says about the products it names was checked against their public documentation on 4 October 2026. Product and company names are trademarks of their owners. Fokals is not affiliated with them or endorsed by them.