Google Cloud

On Google Cloud, Timelake runs inside Cloud Run functions and keeps its tables in a Cloud Storage bucket. Data reaches the functions in one of several ways, depending on how your devices send it. Every design below appends to the same table from the same source folder, so you can start with one and add another later.

DesignDevices sendVisible to queries afterFits
Files to Cloud StorageCSV, Parquet, or JSON fileseach uploadgateways that buffer readings and upload every few minutes
Pub/Sub to Cloud StoragePub/Sub messagesthe file interval (1 to 10 minutes)many small senders; Pub/Sub does the batching
Pub/Sub, pulled every minutePub/Sub messagesabout a minutea steady message stream with no extra files in between

Which to start with. If your gateways can write files, use Files to Cloud Storage: it has the fewest parts, and each file is one commit. If devices send single readings, use Pub/Sub to Cloud Storage, which turns a minute of messages into one file and so one commit. Use Pub/Sub, pulled every minute when you'd rather not keep landing files, or need data within about a minute.

Then scheduled checks read recent data and alert, and maintenance runs every hour. Other designs covers MQTT devices, per-message triggers, and backfills.

Timelake hasn't been tested on Cloud Storage yet (Limitations). It reaches Cloud Storage through the same storage library as S3, and commits use Cloud Storage's generation preconditions.

Cloud Storage or BigQuery tables for Apache Iceberg

Google Cloud has its own way to keep Iceberg tables in your bucket: BigQuery tables for Apache Iceberg.

Cloud Storage bucket, with TimelakeBigQuery tables for Apache Iceberg
DataParquet and Iceberg metadata in your bucketParquet in your bucket; BigQuery keeps the table's metadata
WritersTimelake (CLI, Python, Rust)BigQuery: DML, load jobs, the Storage Write API, Pub/Sub BigQuery subscriptions
CompactionIn the writer, after appends; maintain for a full passBigQuery's storage optimization, billed as compute
ReadersTimelake, DuckDB, and other engines that open Iceberg tables by pathBigQuery; other engines read an exported metadata snapshot, which can lag streamed data
Time-series featuresLatest values, deduplication, rollups, retention by timePlain Iceberg, queried with BigQuery SQL
Runs onAny object store, or local diskGoogle Cloud only

Choose BigQuery tables if your queries already run in BigQuery. Choose Timelake on Cloud Storage for frequent small appends that need fast queries straight away, for time-series queries, or to keep the same setup on other clouds. Files written into a BigQuery-managed table by anything other than BigQuery are not tracked, so Timelake can't write into one.

Other designs

  • Devices over MQTT. Google Cloud IoT Core was retired in 2023, so there is no managed MQTT service to put in front. Run an MQTT broker (on GKE or a VM) with a bridge that publishes to the Pub/Sub topic, then use Pub/Sub to Cloud Storage or Pub/Sub, pulled every minute.
  • A function per message. An Eventarc or push trigger on the topic calls a function per message: simple, and fine for a few messages a minute. Beyond that, use Pub/Sub to Cloud Storage or Pub/Sub, pulled every minute.
  • A long-running consumer. For a stream busy enough to keep a puller running all the time, run the pull loop continuously on GKE or a VM, appending every few seconds.
  • Backfill. Load history from a VM in the same region: gcloud storage cp -r the old files to disk, then timelake import iot.readings ./history --batch-id backfill-2025. Appends of history don't conflict with live ingestion.

Cost

Each commit sends about 7 writes and 2 reads to the lake bucket; Cloud Storage charges writes as Class A and reads as Class B operations. At one commit a minute, that is about 10,000 writes a day. So the batching settings above (upload interval, file interval, pull schedule) are the main cost control. Storage & configuration breaks the requests down. Pub/Sub charges per data volume, and Cloud Run bills for the time each function runs.