BigQuery Data Transfer Service explained
The BigQuery Data Transfer Service loads data into BigQuery on a schedule from SaaS apps, Google ad and analytics products, other clouds and other warehouses. Many connectors are free, the rest are billed in slot-hours, and scheduled queries and dataset copies run on the same machinery.
The BigQuery Data Transfer Service (DTS) is a managed scheduler with a library of connectors. You pick a source, a destination dataset and a schedule, and BigQuery pulls the data in on every run, with no code and no servers to run. It only loads data into BigQuery, never out. Two features you may already use are also built on it: scheduled queries and dataset copies are transfer configurations too.
What it can load
Google’s list, as of its 2026-10-05 update:
| Group | Sources |
|---|---|
| SaaS | Salesforce, Salesforce Marketing Cloud, ServiceNow |
| Marketing | Facebook Ads, HubSpot (Preview), Klaviyo (Preview), Mailchimp (Preview) |
| Payments and commerce | PayPal, Stripe, Shopify (all Preview) |
| Databases and warehouses | Amazon Redshift, Apache Hive Metastore, Microsoft SQL Server (Preview), MySQL, Oracle, PostgreSQL, Snowflake, Teradata |
| Object storage | Cloud Storage, Amazon S3, Azure Blob Storage |
| Google products | Google Ads, Google Ad Manager, Campaign Manager, Display & Video 360, Google Analytics 4, Search Ads 360, Merchant Center (Preview), CSS Center (Preview), Google Play, YouTube Channel, YouTube Content Owner |
Partners also publish connectors on Cloud Marketplace.
We listed the data sources the API reports for a project: 35, including one that Google’s list doesn’t mention, databricks_unity (Databricks Unity Catalog). The API also reports the minimum gap between runs per source, which the docs only give for a few:
| Source | Minimum interval between runs |
|---|---|
| Scheduled query | 5 minutes |
| Cloud Storage, MySQL, PostgreSQL, Oracle, SQL Server, Databricks Unity Catalog, Salesforce, Salesforce Marketing Cloud, ServiceNow, HubSpot, Klaviyo, Shopify, Stripe, PayPal | 15 minutes |
| Hive Metastore | 30 minutes |
| Amazon S3, Azure Blob Storage, Snowflake, Teradata, Mailchimp | 1 hour |
| Google Ad Manager | 4 hours |
| Merchant Center | 6 hours |
| Dataset copy | 12 hours |
| CSS Center | 24 hours |
Google Ads, GA4, Search Ads 360, Display & Video 360, YouTube, Google Play, Campaign Manager and Facebook Ads report no minimum. Campaign Manager and Ad Manager default to a run every 8 hours; every other source defaults to every 24 hours. Redshift reports no schedule at all.
What a transfer does on each run
A transfer configuration has a source, a destination dataset, a schedule and credentials. Each scheduled time creates a run, and the run starts load jobs (and, for some sources, merge jobs) into tables in the destination dataset. A few things follow from that:
- The transfer lives in the destination dataset’s location. The configuration, the staging and the processing all happen there. The location of the source data doesn’t matter. Create the dataset first. For the Teradata migration, the staging bucket in Cloud Storage must be in the same location as the dataset.
- A run is a load job, so load quotas apply. Google gives a formula for how many load jobs a project burns: transfers times tables per transfer times runs per day times the refresh window. A Google Ads transfer creates about 60 tables, Search Ads 360 about 50, so a few of them at a short refresh window can hit the daily load-job quota and make other loads fail with
quotaExceeded. Scheduled queries are not transfers in this sense and don’t count against load limits. - Credentials belong to a transfer owner. The owner can be a user or, for sources that support it, a service account. Runs read the source with the owner’s credentials, so the transfer depends on that identity. Google documents an Update credentials action for changing it.
- Run history is kept for 90 days, then deleted. Logs and run metrics go to Cloud Logging and Cloud Monitoring (the metric resource type is
BigQuery DTS Config: active run count, completed run count and run latency). - DTS jobs use slots from a reservation only if your project, folder or organization is assigned to one with
QUERYorPIPELINEjob types. Dataset copy jobs never use reservation slots.
Cloud Storage transfers are not the same as a load job
A recurring Cloud Storage transfer looks like bq load on a timer, with rules worth knowing:
- The destination table must already exist, and for CSV and JSON you must define its schema. A one-time load can create the table; a recurring transfer can’t.
- The default write preference is
APPEND. An unmodified file is loaded only once. If a file’s last-modified time changes, it is loaded again, which can duplicate rows.MIRRORinstead overwrites the table on each run. - Every file matching the pattern must share one schema. A schema change between runs fails the transfer.
- Archived (non-live) object versions aren’t read.
- Google doesn’t guarantee that files modified during a run are loaded exactly once.
- The minimum interval is 15 minutes. For fresher data, use an event-driven transfer: Cloud Storage notifies Pub/Sub when an object is added, and the transfer runs, with a wait of up to 10 minutes before the next run. Google recommends it for incremental ingestion that is cheap, and the Storage Write API for anything that must be near real time. See Streaming and Loading data.
Backfills
Most connectors let you rerun for a date or date range. You can start one from the console (Run transfer now, or Schedule backfill) with bq mk --transfer_run, or through the startManualRuns API call. The limits are the same everywhere:
- A request covers at most 180 days. For longer, split it into 180-day chunks and wait for each to finish.
- Simultaneous backfill requests aren’t supported.
- How far back you can go depends on the source. Check its transfer guide.
- A large backfill can take hours or days.
What it costs
The DTS charge is compute, in slot-hours, in two parts: orchestration (running the connector) and data loading and processing. Google’s pricing page says:
| Part | Cost |
|---|---|
| Orchestration, free connectors | nothing. Cloud Storage, Amazon S3, Azure Blob Storage, Google Ads, Ad Manager, Campaign Manager, Display & Video 360, GA4, Search Ads 360, YouTube, Merchant Center, CSS Center, Redshift, Teradata, Snowflake migration, Hive |
| Orchestration, paid connectors | slot-hours. GA: Salesforce, ServiceNow, Salesforce Marketing Cloud, Facebook Ads, MySQL, PostgreSQL, Oracle. Preview connectors (Stripe, PayPal, HubSpot, Klaviyo, SQL Server) aren’t charged until they reach GA |
| Google Play | $25 per month per unique package name in the Installs country table, prorated |
| Partner connectors | set by the partner |
| Loading into native tables | free (standard load jobs) |
| Merge into native tables | standard BigQuery rates |
| Loading and merging into Iceberg tables | standard rates for those tables |
For paid connectors the default price list shows $0.06 per slot-hour, and prices vary by region. Google’s rule of thumb for planning is up to 20 slot-hours for each hour a transfer runs, which comes to about $1.20 per run-hour in us-central1. That is an upper bound for budgeting, not a measurement.
Beyond that, you pay normal BigQuery storage and query costs for the data once it lands, plus anything the other side charges. Google calls out AWS and Azure data transfer fees for S3 and Blob transfers, and storage cost for files that stay in your Cloud Storage bucket after loading, because transfers don’t delete them unless you ask (the Cloud Storage option “Delete source files after transfer” is best effort).
To see the total, filter the billing report by the label key goog-bq-feature-type with value DATA_TRANSFER_SERVICE. Google says that from 11 August 2026 all DTS SKUs are unified under the value data_transfer_service, so check which spelling your billing data shows. See labels and billing export for querying it.
Scheduled queries and dataset copies
Both are transfer configurations. Scheduled queries use the data source scheduled_query and are the cheapest way to run recurring SQL: bytes billed as for any query, no DTS fee. Dataset copy (cross_region_copy) copies a dataset to another dataset, including across locations, with a 12-hour minimum between runs. You can find them with the same commands as other transfers:
bq ls --transfer_config --transfer_location=us \
--filter=dataSourceIds:scheduled_query,cross_region_copy
Which tool to use
| You want | Use |
|---|---|
| Daily files from Cloud Storage, S3 or Blob Storage | a DTS transfer (event-driven for files that arrive irregularly) |
| Salesforce, Google Ads, GA4 and similar | the DTS connector, if one exists |
| Recurring SQL inside BigQuery | a scheduled query |
| Moving a warehouse (Teradata, Redshift, Snowflake) once | the DTS migration connectors, then see migrating to BigQuery |
| Rows within seconds from your application | the Storage Write API |
| Applying row changes with upserts and deletes | not DTS schedules: see change data capture |
The Data delivery SLO applies only to scheduled transfers from sources inside Google Cloud. For third-party sources, an outage on their side affects your runs and the SLO doesn’t cover it.