BIGTABLE → STACKIT · ARCHITECTURE
Bigtable migration: designing the wide-column layer
STACKIT has no managed wide-column service, so Bigtable is a design decision before it is a migration. StackToIT classifies the instance as REDESIGN, writes no Terraform for it and names the settings a person must settle: the data model, replication, cluster zones and names. This page lays out the realistic options, what each costs you in operations and rewriting, and how to choose from what your code and your data already tell you.
A Bigtable instance and its policies, assessed
An estate written for this page and assessed by StackToIT on 4 November 2026: one instance with two clusters, a table with two column families, two garbage collection policies and an application profile. The right pane is a verbatim excerpt of engineering/architect-report.md for the instance: the reason, the table it includes and the three warnings about its uncatalogued neighbours. The run wrote no Terraform for any of the four units.
resource "google_bigtable_instance" "telemetry" {
name = "telemetry"
deletion_protection = true
cluster {
cluster_id = "telemetry-ew3-a"
zone = "europe-west3-a"
num_nodes = 3
storage_type = "SSD"
}
cluster {
cluster_id = "telemetry-ew3-b"
zone = "europe-west3-b"
num_nodes = 3
storage_type = "SSD"
}
}
resource "google_bigtable_table" "readings" {
name = "device-readings"
instance_name = google_bigtable_instance.telemetry.name
split_keys = ["a", "m", "t"]
column_family {
family = "metrics"
}
column_family {
family = "meta"
}
}
resource "google_bigtable_gc_policy" "metrics_ttl" {
instance_name = google_bigtable_instance.telemetry.name
table = google_bigtable_table.readings.name
column_family = "metrics"
max_age {
duration = "720h"
}
}
resource "google_bigtable_gc_policy" "meta_versions" {
instance_name = google_bigtable_instance.telemetry.name
table = google_bigtable_table.readings.name
column_family = "meta"
max_version {
number = 1
}
}
resource "google_bigtable_app_profile" "ingest" {
instance = google_bigtable_instance.telemetry.name
app_profile_id = "ingest"
single_cluster_routing {
cluster_id = "telemetry-ew3-a"
allow_transactional_writes = false
}
ignore_warnings = true
}- **Why:** STACKIT has no wide-column database service; row-key design and the HBase/Bigtable client API move to a self-operated store or a redesigned data model.
- **Includes:** `google_bigtable_table.readings`
- **WARNING** (uncatalogued-related): google_bigtable_app_profile.ingest (google_bigtable_app_profile) is linked to this unit but not in the knowledge base; its effect on the migration is not assessed.
- **WARNING** (uncatalogued-related): google_bigtable_gc_policy.meta_versions (google_bigtable_gc_policy) is linked to this unit but not in the knowledge base; its effect on the migration is not assessed.
- **WARNING** (uncatalogued-related): google_bigtable_gc_policy.metrics_ttl (google_bigtable_gc_policy) is linked to this unit but not in the knowledge base; its effect on the migration is not assessed.Four units, none drafted
The table travels with the instance as a facet. The two garbage collection policies and the application profile are separate units classed MANUAL_REVIEW, because they are not in the engine's catalogue: nothing about them is assessed or drafted, and the run says so.
Why the confidence is LOW here
The same instance alone, in the twelve-resource estate of our service mapping page, came out as MEDIUM. Here the architect report lists the instance under the linked units of the uncatalogued garbage collection policies with a confidence cap of LOW. That tells you the policies and the profile need an architect's eyes, not that the instance is more or less portable.
What the run classifies
| Unit | Class and confidence | Why |
|---|---|---|
| Bigtable instance (with its table) | REDESIGN, LOW | STACKIT has no wide-column database service. Row-key design and the HBase or Bigtable client API move to a self-operated store or a redesigned data model. Target named: a self-managed store on SKE, or MongoDB Flex. |
| Garbage collection policy, 30 days (max_age) | MANUAL_REVIEW, LOW | Not in the catalogue. Carries the retention rule of one column family; an architect decides where it lives. |
| Garbage collection policy, one version (max_version) | MANUAL_REVIEW, LOW | Not in the catalogue. Carries the version rule of the other column family. |
| Application profile with single-cluster routing | MANUAL_REVIEW, LOW | Not in the catalogue. Decides which cluster an application talks to; a store without that notion needs the choice made elsewhere. |
Data movement reads DECISION REQUIRED with the mechanism UNKNOWN: the source states neither the size of the data nor its change rate, and the run does not guess them.
The options, with their trade-offs
The first two are the targets the engine names. The last two are general practice the engine does not propose; they fit only when the workload is smaller or colder than a Bigtable deployment suggests.
| Option | What it means | Trade-offs |
|---|---|---|
| Self-managed wide-column store on SKE (the run names Apache Cassandra or HBase as examples) | Closest data model: row or partition keys, column families, timestamped cells | You operate it: upgrades, backups, capacity and repair. The client API changes unless you pick HBase. Highest operational load. |
| MongoDB Flex with a redesigned document model | STACKIT documents it as a managed MongoDB service, compatible with native MongoDB | Key-range access becomes an index or shard-key design. The schema is rewritten, not moved. Check the volume and write rate you actually have against the service. |
| PostgreSQL Flex with partitioned tables (general practice) | Time or device partitions replace row-key ranges | Managed and relational, with a rewrite of every access path. Sensible for moderate volume, not for unbounded writes. |
| Object Storage for cold history (general practice) | Expired or rarely read rows land as files | Cheap and durable, no low-latency lookups. Usually a complement to another option, not a replacement. |
Where each Bigtable construct goes
| Bigtable construct | What it does | What you decide |
|---|---|---|
| Row key | The only indexed value; rows are stored sorted by it, so key design drives how writes spread and how ranges read | Which queries must stay a single range read. Google's schema guidance warns against timestamp-first keys because of hotspots. |
| Column families and qualifiers | Group related columns; each cell holds timestamped versions | Names are open settings in the run. Decide whether versions matter at all. |
| Garbage collection policy | Age and version rules per column family, applied by a background process | The target needs its own expiry. Bigtable can still return expired cells until compaction runs, so check whether anything depends on that. |
| Two clusters in two zones | Replication starts when a second cluster joins; instances with more than one cluster default to eventual consistency | Replication and cluster zone are open settings. Decide the placement of replicas on STACKIT and the consistency your readers accept. |
| Application profile | Routes an application's requests; in the example, single-cluster routing pins ingest to telemetry-ew3-a | Pin each workload to a cluster or accept any; the target store will not have the object. |
How to choose
1. Read the access pattern out of the code
List the queries: point reads by key, prefix or range scans, time-ordered reads per device. Range scans on a composite key are what a wide-column store does best and what every other option must rebuild.
2. Get the numbers the run cannot give you
Data size, change rate and write throughput are not in the Terraform. The data-movement file states that size and change rate are not in the source and that tolerated downtime and recovery point were not provided; collect all of them from the running system before you shortlist anything.
3. State the consistency your readers accept
A multi-cluster Bigtable instance reads eventually consistent by default. If that was a deliberate choice, a single primary with a replica may do; if nobody noticed, say so now.
4. Write down retention as a requirement
The 30-day and one-version rules in the example are requirements, not settings to copy. Name the retention in business terms, then express it in the target.
5. Count the operating cost
A self-managed store buys the closest model and costs a team that can run it. A managed service lowers that cost and raises the rewrite. The run prices neither.
6. Plan the data movement last, not first
Mechanism, window and validation depend on the target. Choose them after the store, with rollback in mind: keep Bigtable readable until the new store has served real traffic.
Questions architects ask
Does STACKIT offer a managed Bigtable equivalent?
The engine finds none: its reason for the instance is that STACKIT has no wide-column database service. The targets it names are a self-managed store on SKE or MongoDB Flex, both after a redesign.
Why are the garbage collection policies MANUAL_REVIEW?
They are not in the engine's catalogue, so nothing about them is assessed or drafted. They still matter, because they hold your retention rules.
Can StackToIT move the Bigtable data?
No. It never moves data. The run lists the instance as a stateful unit with the mechanism undecided, and leaves size, change rate and tolerated downtime to you.
Is a redesign always a rewrite of the application?
It is a rewrite of the data access layer in most cases. Choosing a store with the same model, such as HBase, narrows that change, at the price of running it yourself.
Sources
Your next move: STACKIT.
Tell us about your estate. We show you what StackToIT delivers for it: target architecture, Terraform artifacts and a structured migration plan.