GCP defined flat: the Storage Read API, project against dataset against table, BI Engine, BigQuery materialized views, scheduled queries, time travel and fail-safe, partition expiration, the partition pseudo-columns, on-demand pricing and bytes billed, pull against push subscriptions, BigQuery subscriptions, Dataflow autoscaling and Streaming Engine, PCollections and ParDo, Flex Templates, Dataproc autoscaling and ephemeral clusters, Datastream backfill against CDC, service accounts and Workload Identity, VPC Service Controls, Dataplex, BigLake, plus the ten one-liners every GCP screen opens with.
The Storage Read API, the resource hierarchy, BI Engine, materialized views, scheduled queries, time travel, partition expiration, pseudo-columns, on-demand pricing.
Pub/Sub & Dataflow
5
Pull against push, BigQuery subscriptions, autoscaling and Streaming Engine, Beam's three nouns, Flex Templates.
Dataproc, Datastream & the lake
4
Autoscaling policies and ephemeral clusters, backfill against CDC, Dataplex, BigLake and external tables.
Identity & perimeters
2
Service accounts, Workload Identity, and VPC Service Controls.
Evergreen · asked verbatim
10
The flat form, in the words interviewers use. The one-line service definitions every GCP screen opens with.
What is the BigQuery Storage Read API? How does it differ from running a query, and when does Spark or Dataflow use it?
Why they ask this
It is how every engine outside BigQuery reads tables fast, and candidates confuse it with the query API.
Say this
The Storage Read API reads a table's stored rows directly over gRPC, in parallel streams, as Arrow or Avro batches, with column projection and row filters applied on the server. A query runs through the BigQuery engine and returns a result set through the jobs API. The Storage Read API is what the Spark connector, Dataflow's BigQueryIO and pandas use to pull a large table, and it is billed per byte read rather than per byte scanned by a query.
The reasoning
A read session is created for a table with the columns and an optional filter; it returns a set of streams that a client reads in parallel. Each stream yields Arrow record batches, which Spark converts to partitions without a serialisation hop. Snapshot time is fixed at session creation, so a read is consistent.
The alternative, exporting to Cloud Storage and reading files, is slower, costs an export job, and leaves copies. Paging through query results with the jobs API is limited in throughput and shape. The Storage Read API replaced both for bulk reads.
Pricing is separate from queries: bytes read through the API are billed at a per-TiB rate, with a free monthly allowance, and column projection and filters reduce it. Reading a view or an external table is not supported directly; the connector runs a query to materialise first, which costs query bytes.
The companion is the Storage Write API, the current high-throughput ingestion path with exactly-once semantics through committed streams, replacing the legacy streaming inserts.
The answer most people give
"Spark reads BigQuery by running a SELECT and paging the results." The connector opens Storage Read API streams and pulls Arrow batches in parallel. A query is only used when the source is a view or a filter the API cannot push.
They’ll ask next
A Spark job reads a 2 TB BigQuery table but needs five of 80 columns. Which API feature cuts the cost, and what is billed?
Reported · 2BigQuery architecture (slots, storage, Dremel)IAM & data security
What is the project, dataset, table hierarchy in BigQuery? What does each level own, and what is fixed by a dataset's location?
Why they ask this
The hierarchy decides billing, permissions and where joins are allowed, and the location rule bites in every multi-region setup.
Say this
A project is the billing and IAM boundary and the home of jobs and slots. A dataset is a container inside a project that owns tables, views, routines and models, and it has a fixed location, a region or multi-region, chosen at creation. A table lives in one dataset. Queries can join tables across datasets and projects only when they are in the same location, and a dataset's location cannot be changed after creation.
The reasoning
Full names are `project.dataset.table`. The project that runs a query is the one billed for it. That is how a central data project can expose datasets to consumer projects that pay for their own queries. Quotas, such as concurrent query limits, are per project.
Datasets carry access control and defaults. IAM roles granted on a dataset apply to every table in it; table-level and column-level controls narrow further. A dataset can set default table expiration and default partition expiration, and it can be shared through Analytics Hub as a listing.
Location is the constraint people hit. A dataset in `europe-west2` cannot be joined with one in `US`, and a query that references both fails. Copying a dataset across regions is a Data Transfer Service job, not a `CREATE TABLE AS`. Multi-regions, `US` and `EU`, are the common choice for flexibility within a continent.
Tables are typed: native tables in BigQuery storage, external tables over Cloud Storage or other clouds, BigLake tables, views, materialized views, snapshots and clones. Time travel, partitioning and clustering are table properties.
The answer most people give
"You can move a dataset to another region later." Location is immutable. The fix is a cross-region copy into a new dataset and a cutover of consumers.
They’ll ask next
Finance's dataset is in the EU multi-region and marketing's is in us-central1. What happens on a join, and what are the two ways to make it work?
What is BigQuery BI Engine? What does it accelerate, how is it sized, and what does it not help?
Why they ask this
It is the dashboard-latency answer in BigQuery, and knowing its limits separates reading the brochure from using it.
Say this
BI Engine is an in-memory analysis service inside BigQuery that caches table data in memory and serves repeated, selective queries from dashboards in sub-second time. You reserve a capacity in gigabytes per project and location, and BigQuery decides which tables and columns to cache based on the queries it sees, with preferred tables as a hint. It accelerates Looker Studio, Looker and any client using the API. It does not help queries that scan more than the reservation, heavy joins across large tables, or one-off exploratory SQL.
The reasoning
Dashboards fire the same shape of query many times: filter by date and region, group by a few columns, sum. Running each as a full BigQuery job costs slots and seconds. BI Engine keeps the hot columns in RAM and answers those queries with vectorised execution, bypassing the distributed engine.
The reservation is the control. A project reserves, say, 50 GB in `US`. Queries are accelerated when the data they touch fits in that memory, and fall back to the normal engine when they do not. The query plan shows whether BI Engine was used and, if not, the reason, such as unsupported SQL or insufficient memory.
Acceleration is partial by design: BigQuery accelerates the stages it can and runs the rest normally, so a query may be fast in parts. Supported functions and join shapes are listed in the docs; most dashboard SQL qualifies. Materialized views and BI Engine combine well, the view shrinking what must be cached.
Cost is per gigabyte of reservation per hour, independent of queries. It is worth it when a dashboard audience is large and the queried data is hot and small. A 20 TB fact table is not what it caches; the aggregate over it is.
The answer most people give
"BI Engine makes every BigQuery query faster." It accelerates selective, repeated queries over data that fits its memory reservation. Large scans and ad hoc analytics run on the normal engine.
They’ll ask next
A 500-user Looker Studio dashboard over a 3 TB table is slow. What do you put in front of it, how big a reservation, and what else would you build first?
What is a materialized view in BigQuery? How is it refreshed, what is smart tuning, and what are its restrictions?
Why they ask this
The dump lists materialized views as a BigQuery optimisation lever, and the refresh and rewrite behaviour is what makes them different from other warehouses.
Say this
A BigQuery materialized view is a precomputed result of a query over base tables that BigQuery keeps up to date automatically and incrementally, reading only changed data since the last refresh. Smart tuning means the optimiser rewrites a query against the base table to use the view when it can, so users need not reference the view. Restrictions: the query must be over native or BigLake tables, aggregations are limited to supported functions, and some constructs such as window functions and non-deterministic functions are not allowed, with joins supported only in defined shapes.
The reasoning
`CREATE MATERIALIZED VIEW ds.daily_sales AS SELECT dt, region, SUM(amount) FROM ds.sales GROUP BY 1, 2`. BigQuery refreshes it in the background, within `max_staleness` or at a default interval. At query time it merges the view with recent base-table changes, so results are always current even between refreshes.
Smart tuning is the distinctive part. A dashboard query `SELECT region, SUM(amount) FROM ds.sales WHERE dt = ...` is rewritten to read the view, cutting bytes billed and time, without anyone changing the dashboard. The query plan shows the rewrite.
Costs are the refresh, billed as query bytes or slots, plus the view's storage. Base tables that churn heavily make refresh expensive; setting `max_staleness` lets a view serve slightly stale results without a merge, trading freshness for cost.
Limits that shape use: inner joins are allowed only in defined patterns, and there is no `UNION`, no window function and no `HAVING` on non-aggregated columns. Partitioning aligns with the base table. A view over an external table requires BigLake with metadata caching. Clusters and partitions on the view itself are allowed.
The answer most people give
"A materialized view is a table you refresh with a scheduled query." BigQuery maintains it incrementally and rewrites user queries to use it. A scheduled `CREATE TABLE AS` does neither.
They’ll ask next
Analysts query a raw events table directly and ignore the summary table you built. Which BigQuery feature fixes that without changing their SQL, and what makes it incremental?
What are BigQuery scheduled queries? What service runs them, what parameters can they use, and when are they not enough?
Why they ask this
Scheduled queries are the simplest ELT on GCP, and the boundary where they stop being enough is a judgment check.
Say this
A scheduled query is a SQL statement, usually a DML or a CREATE TABLE AS, that BigQuery runs on a schedule through the BigQuery Data Transfer Service, with the run time available as @run_time and @run_date parameters. It can write to a destination table with a date-templated name or append and overwrite partitions. It is enough for a chain of independent daily transformations; it has no dependency graph, no retries beyond its own, and no cross-query orchestration, which is where Dataform, Composer or dbt take over.
The reasoning
You write `INSERT INTO ds.daily_agg SELECT ... WHERE dt = DATE(@run_date) - 1`, pick a schedule such as every day 06:00, choose a service account to run as, and optionally a destination table with a `{run_date}` template. Each run is a normal query job, billed as usual, visible in the transfer service's run history.
Backfills are built in: you can schedule a run for a range of past dates and `@run_date` takes each value, which is how a corrected transformation is replayed. Notifications on failure go to Pub/Sub or email.
The limits: a scheduled query knows nothing about other scheduled queries, so a chain of four must be timed by hand with gaps. A failure in step two does not stop step three. There is no lineage, and it is SQL only, with no external calls.
Dataform, built into BigQuery, adds the dependency graph with `ref()`, assertions and versioned SQLX. Cloud Composer adds orchestration across services. The usual progression is scheduled queries for one or two tables, Dataform once there is a graph.
The answer most people give
"Scheduled queries are BigQuery's orchestrator." They schedule one statement each with no dependencies between them. An orchestrator knows the order; a scheduled query knows only the clock.
They’ll ask next
Four scheduled queries feed each other and the third one failed at 06:20 while the fourth ran at 06:30. What did the fourth produce, and what tool removes the problem?
What are BigQuery time travel and fail-safe? What are the windows, how do you query or restore, and what is the cost trade-off?
Why they ask this
It is the undo button for a bad load, and the window sizes are asked by number.
Say this
Time travel lets you query or restore a table as it was at any point within a window, 7 days by default and configurable per dataset from 2 to 7 days, using FOR SYSTEM_TIME AS OF or a table copy with a decorator. Fail-safe is a further 7 days after the time travel window during which deleted or changed data is retained and recoverable only by Google Cloud support. Shortening time travel reduces storage cost on tables with heavy churn under the physical storage billing model.
The reasoning
`SELECT * FROM ds.orders FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 2 HOUR)` reads the pre-mistake state. `bq cp ds.orders@-7200000 ds.orders_restored` copies it to a new table using a milliseconds-ago decorator. A dropped table can be restored the same way within the window.
The window is a dataset setting, `max_time_travel_hours`, between 48 and 168. The default is the maximum. The reason to shorten it is cost: with physical storage billing, every deleted or overwritten byte is stored for the whole window, so a table rewritten daily holds seven copies.
Fail-safe adds seven days you cannot reach yourself. It exists for disaster recovery: a support case can restore data up to 14 days after deletion with the default window. It is also billed under physical storage.
Time travel is per table state, not per row lineage, and it does not survive a dataset deletion beyond the window. For long-term point-in-time needs, table snapshots, which are cheap and keep a state indefinitely, are the tool.
The answer most people give
"BigQuery keeps history for 30 days." Time travel is at most 7 days, plus 7 of fail-safe reachable only through support. Longer history needs snapshots or your own design.
They’ll ask next
A merge overwrote a fact table 10 hours ago with bad data. Write the recovery in words, and say what changes if the dataset's window was set to 2 days.
What is partition expiration in BigQuery? How is it set, what does it do, and how does it relate to require_partition_filter?
Why they ask this
It is the retention mechanism of every event table, and pairing it with the filter requirement is the standard design.
Say this
Partition expiration deletes a partition automatically once it is older than a configured number of days, measured from the partition's date or ingestion time. It is set on the table with partition_expiration_days or as a dataset default, and it applies to time-unit partitioned tables. require_partition_filter is a separate option that rejects any query that does not filter on the partition column, which protects against accidental full scans. Together they give bounded storage and bounded query cost.
The reasoning
`CREATE TABLE ds.events (...) PARTITION BY DATE(event_ts) OPTIONS (partition_expiration_days = 90, require_partition_filter = TRUE)`. Each day, partitions older than 90 days disappear without a job, and a query without `WHERE DATE(event_ts) ...` fails with an error instead of scanning everything.
Expiration is per partition, not per row: a partition's age is its boundary date or ingestion time. Deleted partitions enter time travel like any deletion, so storage drops after the window. Changing the setting applies to existing partitions immediately.
The filter requirement has a subtlety: the filter must be on the partition column itself, or on `_PARTITIONTIME` for ingestion-time tables. A filter on a function of the column that BigQuery cannot prune may not satisfy it, and a filter through a joined table does not count.
Dataset-level `default_partition_expiration_days` applies to new tables only. Table expiration, a different setting, deletes the whole table at a time. Clustering is independent and continues to work within surviving partitions.
The answer most people give
"Partition expiration deletes rows older than N days." It deletes whole partitions by their partition date. A row's own timestamp matters only through the column the table is partitioned on.
They’ll ask next
Legal retention is 400 days and the table is partitioned by ingestion time, yet analysts keep scanning the whole thing. Which two options, with which values?
What are _PARTITIONTIME and _PARTITIONDATE in BigQuery? Which tables have them, and what are the __NULL__ and __UNPARTITIONED__ partitions?
Why they ask this
Ingestion-time partitioning is common in landed data, and the pseudo-columns are what make it queryable efficiently.
Say this
_PARTITIONTIME and _PARTITIONDATE are pseudo-columns on ingestion-time partitioned tables. They hold the timestamp or date of the partition a row landed in, truncated to the partition granularity, and they are not stored as regular columns or returned by SELECT star. Filtering on them prunes partitions. The __NULL__ partition holds rows whose partitioning column is null on column-partitioned tables, and __UNPARTITIONED__ holds rows not yet assigned to a partition, such as data in the streaming buffer.
The reasoning
An ingestion-time partitioned table has no user column for the partition; BigQuery assigns rows to the partition of the time they were loaded, by day, hour, month or year. `SELECT * FROM ds.raw WHERE _PARTITIONTIME = TIMESTAMP('2026-11-01')` reads one partition. `_PARTITIONDATE` is the DATE form for daily tables.
You can load into a specific partition with a decorator, `ds.raw$20261101`, which is how a backfill writes yesterday's data into yesterday's partition rather than today's. Querying with a decorator reads just that partition.
`__NULL__` appears on column-partitioned tables: a row whose partition column is null cannot be placed in a date partition, so it lands in `__NULL__`. Those rows are read by queries without a partition filter and invisible to queries with one, which is a classic missing-data bug.
`__UNPARTITIONED__` holds rows in the streaming buffer before they are partitioned, and rows whose partition value is outside the allowed range. Queries filtering on the partition column may not see them for a few minutes after streaming, which matters for near-real-time checks.
The answer most people give
"_PARTITIONTIME is the row's event timestamp." It is the load time, truncated to the partition. Late-arriving events land in the partition of the day they arrived, which is why column partitioning on event time is preferred for analytics.
They’ll ask next
A daily reconciliation finds rows missing from BigQuery that a filtered query cannot see, but an unfiltered count includes. Which special partition are they in, and what caused it?
What is BigQuery's on-demand pricing model, and what are bytes billed? How does it compare with editions and slots, and what reduces bytes billed?
Why they ask this
The dump asks how BigQuery is optimised for cost, and the per-TiB model is the number interviewers expect.
Say this
On-demand pricing charges per byte a query reads from storage: 6.25 USD per TiB in most regions since July 2023, with the first 1 TiB per month free and a 10 MB minimum per table referenced. Bytes billed is that amount rounded up, shown in the job statistics before and after the run. Editions pricing instead buys slots, units of compute, by the slot-hour with autoscaling and optional commitments, and bytes no longer matter. Partition pruning, clustering, selecting fewer columns, materialized views and avoiding SELECT star all reduce bytes billed.
The reasoning
Columnar storage means a query pays only for the columns it references across the partitions it touches. `SELECT *` on a 100-column table reads everything; `SELECT user_id, amount` reads two columns. The dry-run flag, or the estimate in the console, gives bytes processed before you pay.
`LIMIT` does not reduce bytes billed on a native table, because the scan happens before the limit. Clustering does: when a filter hits clustered columns, BigQuery skips blocks, and the actual bytes billed are lower than the estimate, which cannot account for clustering. A partition filter reduces the estimate itself.
The 10 MB minimum per table means a query touching 50 tiny lookup tables bills at least 500 MB. Cached results are free when the same query repeats and the underlying tables have not changed. Storage is billed separately, per GiB-month, with a lower rate for data untouched for 90 days.
Editions, Standard, Enterprise and Enterprise Plus, price slots per hour with autoscaling between a baseline and a maximum, and one- or three-year commitments discount them. The switch makes sense when monthly on-demand spend exceeds what a steady slot reservation would cost, roughly when queries are frequent and predictable.
The answer most people give
"Adding LIMIT 10 makes the query cheap." On-demand billing counts bytes scanned, and the limit applies after the scan. Only partitions, clustering and column selection reduce the scan.
They’ll ask next
A query estimated at 2 TB bills 400 GB. Which table property explains the gap, and why could the estimate not see it?
What is the difference between a pull subscription and a push subscription in Pub/Sub? What is the acknowledgement deadline, and when do you choose each?
Why they ask this
It is the first Pub/Sub question in any GCP loop, and the ack deadline is where duplicates come from.
Say this
With a pull subscription, the subscriber calls Pub/Sub to receive messages, usually with StreamingPull, and controls its own rate. With a push subscription, Pub/Sub sends each message as an HTTPS POST to an endpoint you configure, and the endpoint's response code is the acknowledgement. The acknowledgement deadline, 10 seconds by default and up to 600, is how long a subscriber has to ack before Pub/Sub redelivers. Pull suits high-throughput consumers like Dataflow; push suits serverless endpoints like Cloud Run that cannot hold a connection.
The reasoning
Pull with the client libraries opens a streaming connection, receives batches, and acks each message when processing is done. Flow control settings cap outstanding messages. The client library extends the ack deadline automatically for messages still in flight, up to a configured maximum.
Push removes the need for a running consumer. Pub/Sub POSTs to the endpoint, which must be HTTPS and reachable; a 2xx response acks, anything else or a timeout causes redelivery with exponential backoff. Push rate adapts to the endpoint's success rate. Authentication uses a service account token Pub/Sub attaches.
A message not acked within the deadline is redelivered, possibly to another subscriber, which is the at-least-once guarantee and the source of duplicates. Exactly-once delivery, available on pull subscriptions in a single region, suppresses redelivery of acked messages. Consumers should still be idempotent.
Retention keeps unacked messages for 7 days by default, up to 31, and acked messages can be retained too for seek and replay. Dead-letter topics receive messages redelivered more than a maximum number of times. Filters on attributes let a subscription receive a subset of a topic.
The answer most people give
"Push is faster because Pub/Sub sends immediately." Delivery latency is similar. Push is about who initiates and whether the consumer can hold a connection; throughput and control favour pull.
They’ll ask next
A Cloud Run service processes messages in 30 seconds and sees many duplicates. Which subscription type is it, which setting is at its default, and what is the fix?
What is a BigQuery subscription in Pub/Sub? How does it map messages to columns, and when is it enough instead of Dataflow?
Why they ask this
It removed a Dataflow job from the commonest GCP streaming pattern, and interviewers check whether you know its limits.
Say this
A BigQuery subscription is a Pub/Sub subscription type that writes messages straight into a BigQuery table through the Storage Write API, with no consumer code. If the topic has a schema, fields map to columns; otherwise the message lands in a data column as bytes or JSON, with optional metadata columns for subscription name, message id, publish time and attributes. It is enough when the data needs no transformation before landing; Dataflow is needed for enrichment, windowing, deduplication or routing.
The reasoning
You create the subscription with a destination table and options: use topic schema, write metadata, drop unknown fields. With `use_topic_schema`, an Avro or Protocol Buffer schema on the topic defines the columns; a message that does not fit goes to a dead-letter topic if configured. With `use_table_schema`, the JSON message is matched to the table's columns instead.
Delivery is at-least-once into the table, so duplicates are possible on retries, and the metadata message id is the key for downstream deduplication. There is no ordering guarantee into the table and no transformation step, which is the point and the limit.
Cost is Pub/Sub's per-TiB charge for the subscription plus BigQuery storage; there is no Dataflow job to run and no streaming insert fee beyond the Storage Write API. For a raw landing zone, that is a large saving.
The comparable option is a Cloud Storage subscription, which writes batches of messages to files in a bucket. Both are the "land it first" pattern; Dataflow remains for anything that must happen to the data in flight.
The answer most people give
"A BigQuery subscription is a Dataflow template under the hood." It is a native Pub/Sub feature using the Storage Write API. No job runs, which is why it cannot transform.
They’ll ask next
Events need deduplication and a join to a reference table before landing. Can a BigQuery subscription do it, and what does the alternative pipeline look like?
What is Dataflow autoscaling, and what is Streaming Engine? What signals drive scaling, and what does Streaming Engine move off the workers?
Why they ask this
Dataflow's cost and lag behaviour come from these two features, and they are asked by name.
Say this
Dataflow horizontal autoscaling adds and removes worker VMs during a job: batch jobs scale on the estimated remaining work and worker CPU, streaming jobs on backlog and throughput, within a maximum you set. Streaming Engine moves the shuffle and the pipeline state, windows and timers, out of the worker VMs into a Dataflow backend service, so workers do only user code, scale faster, use smaller machines, and recover state without rebuilding it on the VM. Dataflow Prime adds vertical autoscaling of worker memory.
The reasoning
Without Streaming Engine, each worker holds the state of its keys on its persistent disk, and rescaling means redistributing that state, which is slow. With it, state lives in the service, and adding a worker is just adding compute. Streaming Engine is on by default for new streaming jobs in most regions.
Scaling signals: a streaming job watches the backlog in seconds, how long it would take to drain unprocessed input at current throughput, and CPU. If backlog grows, workers are added up to `maxNumWorkers`; if workers idle, they are removed. Batch jobs estimate total work from input size and progress.
The controls are `--autoscalingAlgorithm`, `--maxNumWorkers`, `--numWorkers` for the start, and worker machine type. Setting the maximum too low leaves lag; too high lets a hot period spend. Streaming Engine is billed per unit of data processed in the service, offsetting lower VM cost.
Dataflow Prime extends this with vertical autoscaling, raising a worker's memory when a stage runs out, and right fitting, assigning different resources per stage. It is the answer to out-of-memory in a ParDo without resizing the whole fleet.
The answer most people give
"Streaming Engine is Dataflow's autoscaler." It is the backend that holds shuffle and state. Autoscaling is a separate feature that Streaming Engine makes faster, because workers no longer carry state.
They’ll ask next
A streaming job's lag grows every evening and recovers at night, and rescaling takes ten minutes. Which feature is probably off, and which setting bounds the cost once it is on?
What are a PCollection, a PTransform and a ParDo in Apache Beam? How do they fit together, and what is a DoFn?
Why they ask this
Beam's three nouns are the vocabulary test for anyone who claims Dataflow experience.
Say this
A PCollection is an immutable, distributed, possibly unbounded collection of elements, each with a timestamp and a window. A PTransform is an operation that takes one or more PCollections and produces one or more: Read, Map, GroupByKey, Window, Combine. ParDo is the core element-wise PTransform: it applies a DoFn, a class with a process method, to each element, emitting zero or more outputs. A pipeline is a graph of PTransforms over PCollections, run by a runner such as Dataflow.
The reasoning
The pipeline reads a source into a PCollection, applies transforms, and writes a sink. `events = p | ReadFromPubSub(topic) | beam.Map(json.loads) | beam.ParDo(EnrichFn()) | beam.WindowInto(FixedWindows(60)) | beam.CombinePerKey(sum) | WriteToBigQuery(table)`. Each pipe produces a new PCollection; nothing is mutated.
`ParDo` is the general worker. The DoFn's `process(self, element)` can yield several outputs, output to tagged side outputs for routing, read side inputs for lookups, and use state and timers for per-key logic. `Map`, `FlatMap` and `Filter` are ParDos with a lambda.
Unbounded PCollections, from Pub/Sub or Kafka, are where windows and watermarks enter. A GroupByKey over an unbounded collection needs a window to know when a key's group is complete, and the watermark says when the window can fire. Bounded collections, from files, use the global window.
The same code runs on the DirectRunner for tests, Dataflow for production, and Flink or Spark through their runners, which is Beam's portability promise. Python, Java and Go SDKs exist; cross-language transforms let a Python pipeline use a Java connector.
The answer most people give
"A PCollection is like a Spark DataFrame." It has no schema requirement, carries a timestamp and window per element, and can be unbounded. The closer analogue is a stream of timestamped records.
They’ll ask next
A ParDo must route malformed events to a dead-letter table while good events continue. Which DoFn feature does that, and what does the pipeline graph look like?
What is a Dataflow Flex Template? How does it differ from a classic template, and how is one built and launched?
Why they ask this
Templates are how Dataflow jobs are deployed without a developer machine, and Flex is the current form.
Say this
A Flex Template packages a Beam pipeline as a Docker image plus a JSON template specification in Cloud Storage. At launch, Dataflow runs the image in a launcher VM, which builds the pipeline graph with the parameters given and submits the job, so any parameter can change at launch and the pipeline code decides the graph. A classic template stores a pre-built graph, so only ValueProvider parameters can vary and the graph is fixed. Flex Templates are built with gcloud dataflow flex-template build and launched with flex-template run or the REST API.
The reasoning
The build step takes your pipeline code and a base image, produces a container, pushes it to Artifact Registry, and writes the spec file with metadata and parameter definitions. The launch step passes parameters such as input topic and output table, and Dataflow handles the rest.
Classic templates staged a serialized graph; anything that shaped the graph, such as the number of sources or a conditional branch, was frozen at staging. Flex Templates run the construction code at launch, so the same template can produce different graphs for different parameters, and runtime parameters need no special types.
Launch latency is higher, because the launcher VM boots and builds the graph before workers start, typically a minute or two. Google's own provided templates, such as Pub/Sub to BigQuery, are published as Flex Templates.
Operationally, Flex Templates are how Composer, Cloud Scheduler or a CI pipeline starts Dataflow jobs: `DataflowStartFlexTemplateOperator` in Airflow passes parameters and waits. Versioning the image tag gives reproducible deployments.
The answer most people give
"A template is a saved job you re-run." It is a packaged pipeline that creates new jobs with new parameters. A Flex Template builds the graph fresh at each launch.
They’ll ask next
A pipeline must read a variable number of Pub/Sub topics chosen at launch. Why does a classic template fail, and what does the Flex Template do differently?
What is a Dataproc autoscaling policy, and what is an ephemeral cluster? What does the policy control, and why are ephemeral clusters the recommended pattern?
Why they ask this
The dump asks for Dataproc against Dataflow trade-offs, and the cluster lifecycle question is where Dataproc cost is decided.
Say this
A Dataproc autoscaling policy is a reusable YAML or API object attached to a cluster that sets minimum and maximum primary and secondary workers, scale-up and scale-down factors, a cooldown period of 2 minutes by default, and a graceful decommission timeout. The cluster scales on YARN pending and available memory. An ephemeral cluster is created for one job or workflow and deleted when it finishes, so you pay only for the run and each job gets a clean, right-sized cluster. Google recommends ephemeral clusters over long-lived shared ones.
The reasoning
The policy says, for example, primary workers 2 to 2 and secondary preemptible workers 0 to 50. It scales up by 1.0 of needed capacity and down by 0.5, with a 2-minute cooldown and a 1-hour graceful decommission. Every cooldown period Dataproc checks YARN's pending memory and adds or removes workers accordingly.
Graceful decommission lets a worker finish its running YARN containers before leaving, which avoids task failures on scale-down. Secondary workers hold no HDFS data, so they can leave freely. Primary workers do, so scaling them down is slower and risky, which is why policies usually fix primaries and scale secondaries.
Ephemeral clusters come from Dataproc Workflow Templates or from an orchestrator: create cluster, submit job, delete cluster, in one template or three Airflow tasks. Cluster scheduled deletion, `--max-idle`, is the safety net that deletes a cluster idle for N minutes. Data lives in Cloud Storage, not HDFS, so a cluster holds nothing to lose.
Dataproc Serverless for Spark removes the cluster entirely: submit a batch, Dataproc provisions executors, bills per second of compute used, and tears down. It is the default suggestion for Spark jobs that need no cluster-level customisation. Billing for clusters is per second with a one-minute minimum, plus Compute Engine.
The answer most people give
"Keep one big Dataproc cluster running and let autoscaling handle cost." A shared cluster idles between jobs, mixes dependencies and still bills its minimum. Ephemeral clusters or Serverless pay only for the job.
They’ll ask next
A nightly Spark job runs 40 minutes on a 24-hour cluster. Describe the ephemeral version in three orchestrator steps and name the setting that protects against a forgotten cluster.
What is Datastream, and what is the difference between its backfill and its CDC stream? Where does it write, and how does the BigQuery destination apply changes?
Why they ask this
Datastream is GCP's managed CDC, and the backfill-versus-stream split is the operational question.
Say this
Datastream is a serverless change data capture service that reads from MySQL, PostgreSQL, Oracle, SQL Server and other sources and writes to Cloud Storage or BigQuery. A backfill reads the current contents of each table as a one-time snapshot; the CDC stream reads the database's log for ongoing inserts, updates and deletes. Backfill can be automatic for all tables or triggered manually per table. The BigQuery destination applies changes as a merge into the target table, with a configurable staleness that trades freshness for cost, or in append-only mode that keeps every change event.
The reasoning
A stream has a source connection profile, a destination connection profile, and a list of objects to include or exclude. On start it can backfill every included table, then switch to CDC from the log position captured at the start, so no change is missed between the two.
The source must be prepared: binary logging in row format on MySQL, logical replication with a publication and replication slot on PostgreSQL, LogMiner or Binary Reader on Oracle. Datastream needs a user with replication privileges and network access through a private connection, allowlisted IPs or a proxy.
To Cloud Storage, events are written as Avro or JSON files with the source metadata, change type and timestamp, which a Dataflow template or Spark job merges into tables. To BigQuery, Datastream creates the tables and applies changes itself, using the Storage Write API's CDC support. `max_staleness` on the target controls how often the merge happens; a lower value costs more.
Backfill is heavy on the source, so it is often run per table during low traffic and for very large tables replaced by a Dataflow or export-based initial load. Monitoring shows freshness, throughput, and the backfill state per object.
The answer most people give
"Datastream polls tables for changes." It reads the database's transaction log, which is what gives it deletes and low latency. Polling is what the log-based approach replaces.
They’ll ask next
A 2 TB table must be replicated to BigQuery with sub-minute freshness and minimal source impact. How do you handle the initial load, and which BigQuery setting controls the merge cadence?
Reported · 2IAM & data securityMonitoring & failure handling
What is Dataplex Universal Catalog? What does it provide for a data lake, and how does it relate to the former Data Catalog?
Why they ask this
Governance questions on GCP land on Dataplex, and the 2025 renaming trips candidates who learned the old names.
Say this
Dataplex Universal Catalog is Google Cloud's data governance and metadata service. It discovers and catalogs data across BigQuery, Cloud Storage and other sources, organises it into lakes and zones with assets, runs data profiling and data quality scans, records lineage, and lets users search business and technical metadata. In 2025 Google merged the standalone Data Catalog into Dataplex and named the result Dataplex Universal Catalog, so the old Data Catalog entries, tags and templates now live in it.
The reasoning
A lake is a logical domain, such as sales. Zones inside it separate raw from curated, with different type rules. Assets attach Cloud Storage buckets and BigQuery datasets to zones. Discovery scans the buckets and registers tables with inferred schemas, including Hive-style partitions, into BigQuery and the catalog.
Data quality scans run rules, such as not null, uniqueness, range and SQL assertions, on a schedule and publish results to the catalog and to BigQuery. Data profiling scans compute column statistics. Both are serverless and are the GCP answer to "how do you monitor data quality" without a third-party tool.
Lineage is captured automatically from BigQuery jobs, Dataflow and Composer, and shown as a graph of which tables fed which. Aspects, the successor to Data Catalog tags, attach structured metadata such as owner, sensitivity and SLA to entries, and are searchable.
Policy integration: Dataplex can apply IAM to assets by zone, and sensitive-data classification from Sensitive Data Protection can land as aspects. It catalogs; enforcement of column-level security is still BigQuery policy tags and IAM.
The answer most people give
"Dataplex is a storage service for the lake." It stores no data. It catalogs, scans and governs data that lives in Cloud Storage and BigQuery.
They’ll ask next
Leadership wants every table to show an owner and a daily quality score. Which Dataplex features deliver each, and where do the results appear?
Reported · 2Cloud Storage layout & classesIAM & data security
What is BigLake, and what is a BigQuery external table? What does a BigLake table add over a plain external table, and what is metadata caching?
Why they ask this
Lakehouse on GCP means BigLake, and the external-table comparison shows whether you know what it fixes.
Say this
A BigQuery external table queries files in Cloud Storage, Amazon S3 or Azure Blob in place, using the caller's permission to the bucket, with no row-level or column-level security and limited performance. A BigLake table is an external table accessed through a connection resource, so BigQuery's service account reads the files and the user needs only BigQuery permissions. That enables row-level and column-level security, fine-grained access from Spark through the Storage API, and metadata caching, which stores file lists and statistics so queries skip listing and prune partitions.
The reasoning
`CREATE EXTERNAL TABLE ds.raw_events WITH CONNECTION proj.region.conn OPTIONS (format = 'PARQUET', uris = ['gs://lake/events/*'], max_staleness = INTERVAL 1 HOUR, metadata_cache_mode = 'AUTOMATIC')` creates a BigLake table. Without `WITH CONNECTION`, it is a plain external table.
The security difference is the point. A plain external table requires every querying user to have `storage.objects.get` on the bucket, so you cannot hide columns or rows. A BigLake table is read by the connection's service account; users get BigQuery grants, policy tags and row access policies as if it were native.
Metadata caching addresses the performance gap. Listing millions of objects on every query is slow; the cache keeps file metadata and lets BigQuery prune by Hive partition and file statistics. `max_staleness` says how old the cache may be; a manual or automatic refresh updates it.
BigLake also covers open table formats: BigLake Iceberg tables in BigQuery, with BigQuery as the catalog and Cloud Storage as storage, readable by Spark through the BigLake metastore. Object tables bring unstructured files into SQL with their metadata. Plain external tables remain for quick, trusted, ad hoc reads.
The answer most people give
"BigLake copies the files into BigQuery storage." The data stays in the bucket. BigLake changes who reads it, the connection's service account, and adds security and caching over it.
They’ll ask next
Analysts need to see Parquet in a bucket but must not see the email column, and they have no bucket permissions. Which table type, and what two BigQuery features apply?
What is a service account in Google Cloud, and what is Workload Identity? Why are service account keys discouraged, and how does a GKE pod or an external system get credentials instead?
Why they ask this
Every job on GCP runs as a service account, and the key question is the security screen.
Say this
A service account is a non-human identity with an email address that workloads run as; IAM roles are granted to it, and it can be attached to Compute Engine VMs, Cloud Run, Dataflow jobs, Composer environments and Cloud Functions, which then obtain short-lived tokens from the metadata server. Keys are long-lived JSON files that anyone holding them can use, so they are discouraged. Workload Identity Federation lets a GKE Kubernetes service account, or an external identity such as a GitHub Actions job or an AWS role, exchange its own token for a Google token, with no key.
The reasoning
Attaching a service account to a resource is the normal path. A Dataflow job runs as its worker service account, and a Composer environment as its environment service account. Each needs only the roles its work requires: BigQuery Data Editor on a dataset, Storage Object Viewer on a bucket.
A downloaded key never expires on its own, is copied into CI systems and laptops, and shows up in leaked repositories. Organisation policies can disable key creation, and most teams do so. The alternative for humans is impersonation: a user with the Service Account Token Creator role mints a short-lived token for the service account, which is audited.
Workload Identity on GKE binds a Kubernetes service account to a Google service account. A pod's token is exchanged for a Google access token by the metadata server, with no secret in the cluster. Workload Identity Federation extends the same exchange to external identity providers through a workload identity pool, letting GitHub Actions deploy with no stored key.
Service accounts are also resources: `iam.serviceAccountUser` lets someone attach one, and `serviceAccountTokenCreator` lets them act as it, both of which are effectively grants of the account's power. Auditing those bindings is part of least privilege.
The answer most people give
"Download a key and put it in the CI secret store." That is a long-lived credential waiting to leak. Workload Identity Federation lets CI exchange its own identity token for a Google token with no key.
They’ll ask next
A GitHub Actions workflow must load files to Cloud Storage. Describe the keyless setup in words and name the two Google resources it needs.
Reported · 2IAM & data securityMonitoring & failure handling
What is a VPC Service Controls perimeter? What problem does it solve that IAM does not, and what are ingress and egress rules?
Why they ask this
It is the data-exfiltration answer on GCP, and the distinction from IAM is the point of the question.
Say this
A VPC Service Controls perimeter is a boundary around a set of projects and Google-managed services, such as BigQuery and Cloud Storage, that blocks API access to those services from outside the perimeter and blocks data from being copied to resources outside it, even when the caller has valid IAM permissions. IAM answers who may call an API; the perimeter answers from where and to where data may flow. Ingress and egress rules punch controlled holes: which identities from which networks may call in, and which resources outside may receive data.
The reasoning
The threat is a credential that is valid but misused: a stolen service account key, or an insider copying a BigQuery table to a personal project. IAM allows it, because the identity has the role. A perimeter around the data projects denies the API call, because the destination or the caller is outside.
Protected services are listed per perimeter; a service not listed is not restricted. Access levels from Access Context Manager define trusted conditions, such as corporate IP ranges or device policy, and are referenced by ingress rules. Dry-run mode logs what would be blocked before enforcement, which is how perimeters are rolled out.
Egress rules allow specific flows out, such as writing to a partner's bucket. Ingress rules allow specific flows in, such as a Composer environment in a shared project calling BigQuery inside. Perimeter bridges connect two perimeters. Misconfigured rules are the commonest cause of mysterious 403s on otherwise correct IAM.
Private Google Access and Private Service Connect let VPC workloads reach Google APIs without public IPs. That pairs with perimeters so that the only path to the data is from inside. Logs for perimeter violations appear in Cloud Audit Logs with a unique id you can look up.
The answer most people give
"VPC Service Controls is a firewall for VPC networks." Firewall rules control VM traffic. A perimeter controls access to Google-managed APIs and data movement between projects, regardless of network.
They’ll ask next
A valid service account copies a BigQuery table to an external project and succeeds. IAM looks correct. Which control was missing, and what rule would allow a legitimate partner export?
What is Google Cloud Storage, and what are its storage classes and consistency guarantees?
Why they ask this
The lake storage definition, with the class minimum durations that interviewers ask by number.
Say this
Cloud Storage is Google Cloud's object store: buckets hold objects addressed by name, with strong global consistency for reads after writes and listings. Storage classes trade storage price for access price and minimum duration: Standard, with no minimum; Nearline, 30 days; Coldline, 90 days; Archive, 365 days. Autoclass moves objects between classes automatically. Buckets are regional, dual-region or multi-region, and Object Lifecycle Management applies rules by age, version or class.
The reasoning
Objects are immutable blobs with metadata; an overwrite creates a new generation, and versioning keeps old generations. There are no directories: the slash is part of the name, and listing by prefix is how folders are simulated, as on S3. Hierarchical namespace buckets, a newer option, add real folder operations for analytics workloads.
Strong consistency for all operations means a file written by Spark is visible to the next job immediately, including in listings. That removed a class of eventual-consistency bugs that other object stores once had.
Classes matter for a lake: raw landing in Standard, older partitions moved to Nearline or Coldline by lifecycle rules, compliance archives in Archive. Retrieval from colder classes costs per GB, and deleting before the minimum duration still bills the minimum. Autoclass automates the moves for unpredictable patterns.
Access is through IAM on buckets, uniform bucket-level access recommended, with signed URLs for temporary access and VPC Service Controls for perimeters. The gsutil tool is superseded by `gcloud storage`; the Storage Transfer Service moves data in bulk from S3 or on premises.
The answer most people give
"Cloud Storage is eventually consistent like older S3." It has been strongly consistent for a long time, including listings. A written object is visible to the next read.
They’ll ask next
Partitions older than 90 days are rarely read but must be kept for three years. Which classes and which lifecycle rules, and what hidden cost applies if a file is deleted early?
What is Google Cloud Dataflow, and when do you choose it over Dataproc?
Why they ask this
The dump names the Dataflow against Dataproc trade-off directly, and the definition sets up the comparison.
Say this
Dataflow is Google Cloud's fully managed runner for Apache Beam pipelines, batch and streaming, with autoscaling, Streaming Engine for state and shuffle, and templates for deployment. You choose it when the pipeline is written in Beam, needs unified batch and streaming semantics with event-time windows and watermarks, or must be serverless with no cluster to operate. Dataproc is chosen for existing Spark or Hadoop code, Spark-specific libraries, interactive notebooks, and workloads where cluster-level control matters.
The reasoning
A Dataflow job takes a Beam pipeline and runs it on worker VMs that Dataflow provisions, scales and removes. There is no cluster to create. Billing is per second of worker vCPU, memory and disk, plus Streaming Engine and shuffle service usage.
Its strengths are streaming: exactly-once processing within the pipeline, event-time windowing with watermarks and late data handling, and stateful per-key processing, all from Beam's model. Pub/Sub to BigQuery with deduplication and windowed aggregation is the canonical job.
Dataproc runs open-source Spark, Flink, Presto and Hadoop on clusters you define, or Spark on Serverless. Spark's ecosystem, Delta and Iceberg support, MLlib, notebooks and the ability to lift existing jobs unchanged are its reasons. It is batch-first in practice, though Spark Structured Streaming runs on it.
The decision usually follows the team: Beam skills and streaming requirements favour Dataflow; Spark skills and existing code favour Dataproc. Google's own guidance positions Dataflow as the default for new streaming pipelines and Dataproc for migrated Spark workloads.
The answer most people give
"Dataflow is Google's Spark." Dataflow runs Beam, a different programming model with unified batch and streaming. Spark on Google Cloud is Dataproc.
They’ll ask next
A team has 40 PySpark jobs and one new real-time fraud stream. Which service for each, and what would change your answer for the stream?
What is Google Cloud Dataproc, and what are its deployment options?
Why they ask this
The managed Spark definition, with the serverless option that changed the default answer.
Say this
Dataproc is Google Cloud's managed service for Apache Spark, Hadoop, Flink, Trino and related open-source engines. Clusters start in about 90 seconds, bill per second with a one-minute minimum, use Cloud Storage instead of HDFS for durable data, and can be ephemeral, created per job and deleted after. Dataproc Serverless for Spark runs a Spark batch or interactive session with no cluster at all. Dataproc on GKE runs Spark on an existing Kubernetes cluster.
The reasoning
A cluster has a master, primary workers and optional secondary workers that are often preemptible or Spot VMs for cost. Initialisation actions and custom images install dependencies. Component gateway exposes the Spark UI and Jupyter without SSH. The Cloud Storage connector makes `gs://` paths behave like HDFS.
Jobs are submitted through the API, `gcloud dataproc jobs submit`, Workflow Templates that create a cluster, run steps and delete it, or Airflow operators. The Dataproc Metastore service provides a managed Hive metastore shared by clusters, and BigLake metastore is the newer alternative for Iceberg.
Serverless for Spark takes a Spark application and runs it with autoscaling executors, no cluster lifecycle and no idle cost. It is the default for scheduled batch Spark; clusters remain for interactive work, non-Spark engines, and jobs needing specific cluster configuration.
Cost control follows from design: ephemeral clusters or Serverless, Spot secondary workers, autoscaling policies, and `--max-idle` deletion. Data in Cloud Storage means a cluster is disposable.
The answer most people give
"Dataproc stores your data in HDFS on the cluster." HDFS exists but is ephemeral with the cluster. Durable data goes in Cloud Storage, which is what makes deleting the cluster safe.
They’ll ask next
Name the three Dataproc deployment options and say which one you reach for first for a nightly PySpark batch.
EvergreenReported · 2Bigtable vs Spanner vs Cloud SQL
What is Cloud Bigtable, and when is it the right store compared with Spanner and Cloud SQL?
Why they ask this
The three database names are compared in every GCP loop, and Bigtable's row-key design is the detail that matters.
Say this
Bigtable is a wide-column NoSQL database for very large, sparse tables with single-digit millisecond reads and writes by row key, scaling linearly by adding nodes and compatible with the HBase API. It is right for time series, IoT, user profiles and feature stores at petabyte scale with simple key-based access. Spanner is a relational, globally consistent SQL database with transactions across rows; Cloud SQL is managed MySQL, PostgreSQL or SQL Server for conventional applications at moderate scale.
The reasoning
A Bigtable table has one index: the row key. Rows are sorted by key, and performance comes from designing the key so that reads are contiguous ranges and writes spread across nodes. A key such as `device#reversed_timestamp` avoids hotspotting on the newest data while keeping a device's history together.
Columns are grouped in column families, and each cell is versioned by timestamp. There are no joins, no secondary indexes except through separate tables, and no transactions beyond a single row. Garbage collection policies expire old versions.
Capacity is nodes per cluster; each node serves a throughput of reads and writes, and replication across clusters gives availability and locality. Autoscaling adjusts nodes on CPU and storage. Integration with Dataflow and BigQuery external queries connects it to analytics.
The choice: Bigtable for key-based access at huge scale and high write rates. Spanner when you need SQL, secondary indexes and strong consistency across regions with transactions. Cloud SQL when a single-region relational database of a few terabytes is enough and compatibility matters. Firestore is the document option for application data.
The answer most people give
"Bigtable is a big relational table." It is a key-value wide-column store with no SQL joins or multi-row transactions. The relational options are Spanner and Cloud SQL.
They’ll ask next
Sensor readings arrive at a million writes per second and are read by device over time ranges. Which store, and what does the row key look like?
EvergreenReported · 2Bigtable vs Spanner vs Cloud SQLDatastream & CDC
What is Cloud SQL, and how does a data engineer get data out of it?
Why they ask this
The managed relational definition, with the extraction paths a pipeline actually uses.
Say this
Cloud SQL is Google Cloud's managed relational database service for MySQL, PostgreSQL and SQL Server: Google handles provisioning, patching, backups, high availability through a standby in another zone, and read replicas. A data engineer extracts from it by Datastream for log-based CDC, by federated queries from BigQuery for small lookups, by scheduled exports to Cloud Storage, or by batch reads from Dataflow or Spark through JDBC, ideally against a read replica.
The reasoning
An instance has a machine type, storage that can auto-grow, a region and zone, and optional high availability with synchronous replication to a standby. Point-in-time recovery uses backups plus transaction logs. Connections go through private IP, the Cloud SQL Auth Proxy or the connectors, which handle TLS and IAM authentication.
For analytics, the rule is not to query the primary. Read replicas take reporting and extraction load. Datastream reads the log, so it adds little load and captures deletes; it requires logical replication on PostgreSQL or binary logging on MySQL, which are instance flags.
BigQuery federated queries, `EXTERNAL_QUERY('connection', 'SELECT ...')`, run SQL on the Cloud SQL instance from BigQuery and return results, suitable for small reference tables and not for bulk. Exports to Cloud Storage as CSV or SQL dump are the simple nightly path.
Limits that shape design: instance size caps storage at tens of terabytes, connection counts are finite, and long analytical queries hurt the application. The pattern is operational data in Cloud SQL, analytics in BigQuery, connected by CDC.
The answer most people give
"Point the BI tool at Cloud SQL since it is managed and scales." It is an operational database with finite connections and storage. Analytical load belongs in BigQuery, fed by CDC or exports.
They’ll ask next
A pipeline needs every change from a Cloud SQL for PostgreSQL database in BigQuery within a minute. Which service, and which instance flag must be on first?
What is IAM in Google Cloud, and how do principals, roles and the resource hierarchy fit together?
Why they ask this
The permission model definition, and the hierarchy inheritance rule is what interviewers check.
Say this
Google Cloud IAM controls who, a principal, has what access, a role, on which resource. Principals are Google accounts, service accounts, groups, domains and federated identities. Roles are bundles of permissions: basic roles like Owner and Editor, predefined roles per service like BigQuery Data Viewer, and custom roles. A policy is a set of bindings of principals to roles on a resource, and policies are inherited down the hierarchy from organisation to folder to project to resource, with the effective access being the union.
The reasoning
Granting `roles/bigquery.dataViewer` on a project gives read on every dataset in it; granting it on one dataset limits it there. Because inheritance is additive, a role granted at the folder level cannot be removed at the project level, which is why broad grants high in the hierarchy are dangerous.
Basic roles are too coarse for production: Editor includes thousands of permissions across all services. Predefined roles follow least privilege per service, and custom roles pick exact permissions when none fits. Conditions add attributes, such as resource name prefixes or time, to a binding.
Deny policies, newer, override allows for listed permissions and principals, giving the explicit-deny concept. Organisation policy constraints restrict what resources can be created or configured, such as disabling service account key creation, separate from IAM.
For data access specifically, BigQuery adds dataset, table, row and column controls on top of IAM; Cloud Storage uses IAM on buckets with uniform access recommended. Policy Analyzer and IAM Recommender show who has access and which grants are unused, which is how least privilege is maintained.
The answer most people give
"You can deny a role at the project that was granted at the folder." Standard IAM is additive down the hierarchy. Only a deny policy, or removing the higher grant, takes it away.
They’ll ask next
An analyst group has Editor on the project from a folder-level binding. What two things are wrong with that, and how do you reach least privilege?
EvergreenReported · 2IAM & data securityBigQuery cost & pricing models
What is a project in Google Cloud, and how do teams structure projects for data platforms?
Why they ask this
The project is the unit of everything on GCP, and the structuring question tests practical experience.
Say this
A project is the fundamental organising unit in Google Cloud: it owns resources, has a unique id, is linked to one billing account, enables APIs, holds IAM policies and is subject to quotas. Projects sit under folders and an organisation. Data platforms commonly separate projects by environment, dev, test and prod, and by function, with data storage projects that hold BigQuery datasets and buckets, compute projects that run Dataflow and Composer, and consumer projects whose queries are billed to the consuming team.
The reasoning
Every API call targets a project, and the project's enabled APIs, quotas and billing apply. BigQuery query quotas, Dataflow job limits and Pub/Sub throughput quotas are per project, so a busy shared project can throttle unrelated teams.
Separating storage from compute projects lets data live in a few governed projects while many teams run their own jobs and pay their own bills. BigQuery's model supports this directly: the querying project pays, the data project only grants access.
Folders group projects for policy inheritance and billing roll-up: a data platform folder with prod and non-prod subfolders is typical, with organisation policies applied at the folder. Shared VPC lets a host project own the network that service projects attach to.
Project ids are permanent and globally unique, and deleting a project schedules it for removal after 30 days. Labels on projects drive cost allocation reports in Billing export to BigQuery, which is itself a dataset in a project.
The answer most people give
"A project is like a folder for organising resources." It is the billing, quota, API and IAM boundary. Folders are the organising layer above projects.
They’ll ask next
Two teams in one project keep hitting each other's BigQuery concurrent query quota. What structure fixes it, and who pays for queries afterwards?
What are Cloud Logging and Cloud Monitoring, and how does a data pipeline use them?
Why they ask this
The observability definition, with the sink and alert mechanics a pipeline relies on.
Say this
Cloud Logging collects logs from every Google Cloud service and from your code, stores them in log buckets with a default retention of 30 days, lets you query them with the Logs Explorer, and routes them through sinks to BigQuery, Cloud Storage or Pub/Sub. Cloud Monitoring collects metrics, hosts dashboards, and fires alerting policies to notification channels. A pipeline uses Logging for Dataflow and Composer task logs and audit logs, log-based metrics to count errors, and Monitoring alerts on lag, job failures and freshness.
The reasoning
Audit logs, admin activity and data access, record who did what to BigQuery and Cloud Storage, and are the source for access reviews. Data access logs for BigQuery are on by default; for Cloud Storage they must be enabled. A sink of audit logs to BigQuery makes them queryable with SQL.
Log-based metrics turn a filter such as `severity=ERROR AND resource.type=dataflow_step` into a counter you can alert on. Dataflow emits its own metrics, system lag and backlog, which Monitoring charts; Pub/Sub exposes oldest unacked message age, the freshness alert for any streaming pipeline.
Alerting policies compare a metric against a threshold over a window and notify Slack, PagerDuty, email or Pub/Sub. Composer surfaces task failures as metrics and logs per DAG. Uptime checks probe endpoints. SLOs can be defined on custom metrics for data freshness.
Retention and cost are controlled with log buckets, exclusion filters for noisy logs, and sinks to cheaper storage. The Logging and Monitoring pair is what Google calls the Cloud Operations suite, formerly Stackdriver.
The answer most people give
"Cloud Logging stores logs forever for free." The default bucket keeps 30 days and ingestion is billed beyond a free allowance. Long retention needs a sink to Cloud Storage or BigQuery.
They’ll ask next
A streaming pipeline must page someone when data is more than five minutes stale. Which Pub/Sub metric, which Monitoring object, and where do the Dataflow error logs go for later analysis?
What is Dataform, and how does it compare with dbt on BigQuery?
Why they ask this
Dataform is the built-in transformation layer in BigQuery, and the dbt comparison is how candidates place it.
Say this
Dataform is a transformation framework built into BigQuery for defining SQL workflows as code. You write SQLX files, SQL with a config block and JavaScript templating, declare dependencies with ref, add assertions as tests, and Dataform compiles them into a dependency graph and runs them in BigQuery on a schedule, with git integration in the console. It is the same idea as dbt, SQL models with refs, tests and a DAG, but it is BigQuery-only, hosted inside BigQuery at no extra charge, and templated with JavaScript rather than Jinja.
The reasoning
A SQLX file looks like `config { type: "table", schema: "marts" } SELECT ... FROM ${ref("stg_orders")}`. Types include table, view, incremental and assertion. Incremental tables use a `${when(incremental(), ...)}` guard, comparable to dbt's `is_incremental()`.
Repositories connect to GitHub, GitLab or Bitbucket, or use a Dataform-hosted repo. Development workspaces give each developer their own schema. Release configurations compile a branch; workflow configurations run the compiled graph on a cron or through the API, which Composer can also trigger.
Assertions are SQL that must return zero rows, plus built-in `uniqueKey`, `nonNull` and `rowConditions` in config. Dataform records run history and lineage into Dataplex. Pricing is just the BigQuery queries it runs.
Against dbt: dbt is multi-warehouse, has a vast package ecosystem, Jinja, unit tests, and dbt Cloud or your own orchestrator. Dataform is simpler to adopt on a pure BigQuery stack and needs no infrastructure. Teams with existing dbt projects keep dbt; BigQuery-only teams starting fresh often pick Dataform.
The answer most people give
"Dataform is Google's ETL tool for loading data." It transforms data already in BigQuery with SQL, like dbt. Loading is Datastream, the Storage Write API, transfers or Dataflow.
They’ll ask next
A BigQuery-only team has six scheduled queries that depend on each other. What does moving them to Dataform add, and what does it cost?
What is Cloud Run, and what are Cloud Run jobs? Where do they fit in a data pipeline?
Why they ask this
Cloud Run is the serverless container answer on GCP, and jobs made it relevant to batch work.
Say this
Cloud Run runs containers without servers. A Cloud Run service receives HTTP requests or Pub/Sub pushes and scales from zero to many instances with the load, billed per request and per 100 milliseconds of instance time; request timeouts go up to 60 minutes. A Cloud Run job runs a container to completion with no HTTP, as one or many parallel tasks, with task timeouts up to 24 hours, started manually, on a Cloud Scheduler cron, or from Workflows or Composer. In pipelines, services handle webhooks and push subscriptions, and jobs run containerised batch steps such as a Python extraction or a dbt run.
The reasoning
A service is a container image plus a revision configuration: CPU, memory up to 32 GB, concurrency per instance, minimum instances to avoid cold starts, and a service account. Traffic can split between revisions. It is the natural target for a Pub/Sub push subscription or an EventBridge-style Eventarc trigger on Cloud Storage object creation.
A job runs the same kind of image but exits when done. `--tasks 50 --parallelism 10` runs 50 tasks, 10 at a time, each receiving its index in an environment variable, which is a simple way to shard a backfill. Jobs have retries per task and a timeout per task.
Compared with Cloud Functions, now Cloud Run functions, you bring any runtime and system packages in the image. Compared with Dataflow or Dataproc, it is single-container compute with no distributed engine. It fits tasks that a single machine finishes: API extraction, small transforms, dbt or Dataform invocation, notifications.
Cloud Run connects to a VPC through Direct VPC egress or a connector to reach Cloud SQL and private services. It runs as a service account for IAM, and logs to Cloud Logging. Billing to zero when idle is what makes it the glue of choice over an always-on VM.
The answer most people give
"Cloud Run is only for web services." Cloud Run jobs run containers to completion with no HTTP at all, up to 24 hours per task, with parallel tasks for sharding batch work.
They’ll ask next
A nightly job calls a partner API for 2,000 accounts and takes three hours single-threaded. How would Cloud Run jobs run it in 20 minutes, and what tells each container its share?