This article explains a best-practice Snowflake pattern for transforming an SCD2 Bronze layer into a non-SCD Silver layer that exposes clean, current-state data. By retaining full historical truth in Bronze and using Streams, Tasks, and incremental MERGE logic, organisations can efficiently materialise one-row-per-entity Silver tables optimised for analytics. The approach simplifies governance, reduces cost, and delivers predictable performance for BI, ML, and regulatory reporting, while preserving complete auditability required in highly regulated financial services environments.
Contents
- Contents
- Introduction: How to Transform Historical Change Data into Clean, Simple, Current-State Views Using Streams, Tasks, and Micro-Partitioning
- 1. Why Move from an SCD2 Bronze Layer to a Non-SCD Silver Layer?
- 2. Core Snowflake Capabilities That Enable This Pattern
- 3. How to Build a Non-SCD Silver Layer from an SCD2 Bronze Table
- 3.1 Step 1: Maintain SCD2 in the Bronze Layer Using MERGE + STREAMS
- 3.2 Step 2: Use Tasks to Process Only Incremental History
- 3.3 Step 3: Select the Current Version Only
- 3.4 Step 4: Simplify the Schema for Analytics
- 3.5 Step 5: Deduplicate Using Window Functions (If Needed)
- 3.6 Step 6: Materialise the Silver Table
- 3.7 Step 7: Optimise Micro-Partition Clustering (Optional but Recommended)
- 4. Example Bronze to Silver Pipeline in Snowflake
- 5. Why This Pattern Works So Well in Snowflake
- 5.1 Efficient Incremental Processing
- 5.2 Simplified Governance
- 5.3 Strong Alignment with Data Mesh
- 5.4 Optimal Cost Control
- 5.5 Predictable, User-Friendly Analytics
- 5.6 Operational Resilience and Recoverability
- 5.7 Operational Monitoring and Observability
- 5.8 Alternative Approach: Using Dynamic Tables for the Silver Layer
- 6. Summary: Turning Historical Truth into Analytical Clarity
Introduction: How to Transform Historical Change Data into Clean, Simple, Current-State Views Using Streams, Tasks, and Micro-Partitioning
Modern data platforms in regulated environments must satisfy two competing demands: exhaustive historical traceability and simple, performant access to current data. In Snowflake, this tension is resolved not by compromise, but by deliberate architectural separation. This introduction frames the challenge, explains why SCD2 remains essential at ingestion, and sets up the rationale for deriving a clean analytical layer without sacrificing auditability or control.
Snowflake’s cloud-native architecture has made it one of the most widely adopted platforms in UK Financial Services, especially for organisations modernising their data warehousing and regulatory reporting capabilities.
A common and highly effective design pattern in Snowflake lakehouse architectures is separating:
- Bronze layer → SCD2 history
- Silver layer → non-SCD, current-state data
This approach balances the need for full historical traceability with the practical requirement for clean analytical data, especially for BI dashboards, Data Products, ML models, and reporting.
This article explains how to implement this pattern in Snowflake, why it is beneficial, and how to build a reliable, scalable, cost-efficient Silver layer directly from an SCD2 Bronze layer.
This is part 6 of a related series of articles on using SCD2 at the bronze layer of a medallion based data platform for highly regulated Financial Services (such as the UK).
1. Why Move from an SCD2 Bronze Layer to a Non-SCD Silver Layer?
While SCD2 tables are invaluable for preserving historical truth, they are rarely the format that downstream users actually want to work with. This section establishes the practical gap between compliance-driven data capture and everyday analytical consumption, explaining why different layers must serve different purposes—and why forcing one to do both creates unnecessary complexity.
An SCD2 Bronze layer is the backbone of historical truth.
It captures:
- Every change
- Every version
- Every effective timestamp
- Every correction, backfill, and upstream anomaly
This makes it perfect for audit, compliance (FCA/PRA), AML/KYC lineage, and customer remediation.
However, historical data is not the optimal structure for everyday analytics.
BI users, data scientists, and downstream Data Products usually want:
- One row per entity
- No historical columns
- No effective dates
- No version numbers
- No need to reason about temporal joins
Thus:
Bronze exists for history; Silver exists for usability.
Snowflake provides excellent native tooling, Streams, Tasks, Time Travel, micro-partition pruning, that makes this transition simple and scalable.
2. Core Snowflake Capabilities That Enable This Pattern
This pattern is not theoretical; it is made viable by Snowflake’s underlying architecture. Before diving into implementation, it is important to understand which native platform features make incremental, history-aware transformations efficient, reliable, and cost-effective. This section introduces the Snowflake capabilities that quietly do the heavy lifting behind the scenes.
Snowflake’s strengths align neatly with the Bronze → Silver workflow.
Together, these capabilities make Snowflake a natural fit for SCD2 ingestion and current-state simplification.
2.1 Streams
Track changes in the Bronze SCD2 table without scanning the whole dataset.
Streams provide a persistent, ordered change feed on top of Snowflake tables, exposing row-level inserts, updates, and deletes without requiring a full table scan. When applied to an SCD2 Bronze table, a Stream naturally captures only the rows affected by new versions being inserted or existing versions being expired.
This is critical for the Bronze → Silver pattern. Instead of repeatedly re-evaluating the entire historical dataset to determine the current state, downstream transformations can react only to incremental changes. This ensures that Silver refresh logic remains proportional to change volume rather than total data size, keeping processing time and cost predictable even as historical depth grows.
2.2 Tasks
Run scheduled incremental transformations to build and refresh Silver tables.
Tasks provide the scheduling and execution layer that turns incremental change capture into an automated pipeline. By running on a defined cadence, Tasks consume data from Streams and apply controlled, idempotent transformations to the Silver layer.
In this pattern, Tasks ensure that Silver tables are continuously aligned with the latest Bronze state without human intervention. Because Tasks only operate on Stream deltas, they avoid unnecessary MERGE operations and full scans, making the pipeline resilient to scale and well-suited to regulated environments where repeatability and operational transparency are essential.
2.3 Micro-Partitioning
Automatically handles clustering, pruning, and file optimisation.
Snowflake’s automatic micro-partitioning underpins the performance characteristics of both Bronze and Silver layers. Data is physically organised into micro-partitions based on ingestion and clustering behaviour, enabling efficient pruning during query execution.
For SCD2 Bronze tables, this allows large volumes of historical data to remain queryable without degrading performance. For Silver tables, micro-partition pruning ensures fast point-lookups and joins on business keys, even as row counts increase. Importantly, this optimisation is largely automatic, reducing the need for manual tuning while still supporting predictable analytical performance.
2.4 Time Travel
Protects against ingestion errors and allows point-in-time reconstruction.
Time Travel provides built-in access to previous table states, offering a safety net for ingestion errors, faulty transformations, or upstream data corrections. In the context of an SCD2 Bronze layer, Time Travel complements historical modelling by allowing point-in-time inspection beyond what is explicitly encoded in SCD2 columns.
For the Bronze → Silver workflow, Time Travel supports operational resilience. Pipelines can be recovered from mistakes, Silver tables can be rebuilt from known-good Bronze states, and audit or investigation use cases can reconstruct data as it appeared at specific moments in time—all without external backups or complex recovery procedures.
2.5 External Tables + Storage Integration
Allow low-cost long-term history storage if needed.
Snowflake’s support for external tables and cloud storage integration enables flexible cost management for long-term historical data. While the Bronze layer often remains fully queryable, older or less frequently accessed history can be tiered to lower-cost storage without breaking lineage or accessibility.
This capability allows organisations to preserve complete historical truth while optimising storage costs—an especially important consideration in Financial Services, where regulatory retention requirements are long, but access patterns are uneven. Together with Time Travel and micro-partitioning, this ensures that historical depth does not become an operational or financial burden.
3. How to Build a Non-SCD Silver Layer from an SCD2 Bronze Table
This section describes a standard, production-tested pattern for deriving a current-state Silver table directly from an SCD2 Bronze table in Snowflake. The approach assumes that historical correctness is enforced upstream and that Silver exists purely to expose a simplified, analytics-ready view of that history.
3.1 Step 1: Maintain SCD2 in the Bronze Layer Using MERGE + STREAMS
The Bronze layer is responsible for capturing every change emitted by the source system. A typical SCD2 Bronze table for a customer domain might look like this:
CREATE TABLE bronze_customers_scd2 (
customer_sk NUMBER AUTOINCREMENT,
customer_id VARCHAR, -- natural business key
customer_name VARCHAR,
address_line_1 VARCHAR,
address_line_2 VARCHAR,
city VARCHAR,
postcode VARCHAR,
effective_from TIMESTAMP_NTZ,
effective_to TIMESTAMP_NTZ,
is_current BOOLEAN,
record_hash VARCHAR,
load_ts TIMESTAMP_NTZ
);
Incoming CDC or snapshot data is merged into this table using SCD2 logic that expires the previous version and inserts a new one when a change is detected. Once this table is established, a Stream is created to capture incremental changes:
CREATE OR REPLACE STREAM bronze_customers_stream
ON TABLE bronze_customers_scd2;
This Stream will surface only rows that are inserted or updated by the SCD2 process, making it the foundation for incremental Silver processing.
3.2 Step 2: Use Tasks to Process Only Incremental History
A Snowflake Task consumes changes from the Stream and incrementally maintains the Silver table. The Silver table intentionally holds only the current version of each customer:
CREATE TABLE silver_customers (
customer_id VARCHAR,
customer_name VARCHAR,
address_line_1 VARCHAR,
address_line_2 VARCHAR,
city VARCHAR,
postcode VARCHAR,
last_updated_ts TIMESTAMP_NTZ
);
The Task performs a MERGE driven entirely by Stream deltas:
CREATE OR REPLACE TASK silver_customers_refresh
WAREHOUSE = etl_wh
SCHEDULE = '5 MINUTE'
AS
MERGE INTO silver_customers s
USING (
SELECT
customer_id,
customer_name,
address_line_1,
address_line_2,
city,
postcode,
is_current,
effective_from
FROM bronze_customers_stream
) b
ON s.customer_id = b.customer_id
WHEN MATCHED AND b.is_current = FALSE THEN
DELETE
WHEN MATCHED AND b.is_current = TRUE THEN
UPDATE SET
customer_name = b.customer_name,
address_line_1 = b.address_line_1,
address_line_2 = b.address_line_2,
city = b.city,
postcode = b.postcode,
last_updated_ts = b.effective_from
WHEN NOT MATCHED AND b.is_current = TRUE THEN
INSERT (
customer_id,
customer_name,
address_line_1,
address_line_2,
city,
postcode,
last_updated_ts
)
VALUES (
b.customer_id,
b.customer_name,
b.address_line_1,
b.address_line_2,
b.city,
b.postcode,
b.effective_from
);
This logic ensures:
- Expired Bronze versions are removed from Silver
- New current versions overwrite or insert cleanly
- No historical rows ever persist in Silver
- Only Stream-emitted deltas are processed
3.2.1 Initial Silver Bootstrap
For the initial load, before the Stream contains data, Silver tables are typically bootstrapped using a one-off MERGE or CREATE TABLE AS SELECT from the Bronze SCD2 table filtered to the current version. Once the initial state is materialised, the Stream-driven Task takes over, ensuring that only incremental changes are applied going forward.
3.3 Step 3: Select the Current Version Only
SCD2 Bronze tables typically identify the active row using either a boolean flag or an open-ended effective date. Both patterns are common and equivalent in practice.
Examples:
SELECT *
FROM bronze_customers_scd2
WHERE is_current = TRUE;
or
SELECT *
FROM bronze_customers_scd2
WHERE effective_to = '9999-12-31';
This filter defines the semantic contract between Bronze and Silver: Silver represents only the current business state.
3.4 Step 4: Simplify the Schema for Analytics
Silver tables intentionally remove all SCD2 control fields and technical metadata. Columns such as effective_from, effective_to, is_current, surrogate keys, and row hashes have no analytical value for most consumers.
Instead, Silver focuses on:
- Clean business attributes
- Consistent data types
- Intuitive naming
- Stability over time
This makes Silver tables easier to:
- Join
- Document
- Govern
- Expose as domain data products
Silver is designed to be consumed without requiring users to understand how history is modelled upstream.
3.5 Step 5: Deduplicate Using Window Functions (If Needed)
Even in well-designed SCD2 pipelines, edge cases can arise:
- Upstream replays
- Identical updates within the same timestamp
- Schema-driven reprocessing
- Late-arriving corrections
To defensively enforce uniqueness in Silver, window functions can be applied when materialising from Bronze:
SELECT
customer_id,
customer_name,
address_line_1,
address_line_2,
city,
postcode,
effective_from AS last_updated_ts
FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY effective_from DESC, load_ts DESC
) AS rn
FROM bronze_customers_scd2
WHERE is_current = TRUE
)
WHERE rn = 1;
This guarantees:
- Exactly one row per business key
- Deterministic selection of the latest version
- Protection against duplicate current rows
3.6 Step 6: Materialise the Silver Table
Silver tables should be fully materialised rather than exposed as views. This provides:
- Predictable query performance
- Stable cost characteristics
- Clear ownership and lineage
- Strong governance controls
CREATE OR REPLACE TABLE silver_customers AS
SELECT
customer_id,
customer_name,
address_line_1,
address_line_2,
city,
postcode,
effective_from AS last_updated_ts
FROM bronze_customers_scd2
WHERE is_current = TRUE;
Materialisation ensures that Silver behaves as an enterprise-grade analytical asset rather than a fragile abstraction over historical complexity.
3.7 Step 7: Optimise Micro-Partition Clustering (Optional but Recommended)
Although Snowflake manages micro-partitions automatically, explicit clustering can improve performance for common access patterns, particularly joins and point lookups.
For customer-centric domains:
ALTER TABLE silver_customers
CLUSTER BY (customer_id);
Clustering helps ensure consistent query performance as data volumes grow, especially when Silver tables form the backbone of downstream analytical models and reporting workloads.
4. Example Bronze to Silver Pipeline in Snowflake
Concepts become clearer when seen in motion. This section walks through the end-to-end flow of data across the medallion layers, illustrating how changes originate in Bronze, are incrementally processed, and ultimately surface as stable, analytics-ready Silver tables that feed business-facing workloads.
Below is a high-level flow of the architecture.
Bronze (SCD2 Historical Layer)
The flow begins in the Bronze layer, where data is ingested from source systems as CDC feeds or periodic snapshots. Each load is processed through an SCD2 MERGE operation, closing out prior versions and inserting new ones with appropriate effective dates and current-state indicators. At this point, the Bronze table contains a complete, append-only record of every change ever observed.
A Stream defined on the Bronze SCD2 table captures only the rows affected by each ingestion cycle. This includes newly inserted current versions as well as records that have transitioned from current to historical. Crucially, the Stream does not expose unchanged rows, ensuring that downstream processing remains incremental regardless of total table size.
- Ingest CDC/snapshots from source
- Apply SCD2 MERGE
- Maintain full history
- Stream changes via STREAM
Silver (Current-State Analytical Layer)
A scheduled Task consumes data from the Stream at a defined interval. During each execution, the Task evaluates the incoming changes and applies targeted updates to the Silver table. Rows representing expired versions are removed or superseded, while rows representing new current versions are inserted or updated. At no point does the Task need to reprocess the full Bronze dataset.
As part of this transformation, SCD2-specific metadata—such as effective dates, version numbers, and current-state flags—is intentionally discarded. The resulting Silver table contains exactly one row per business entity, with a stable, analytics-friendly schema designed for consumption rather than lineage.
Optional deduplication logic may be applied defensively to handle reprocessing scenarios, upstream replay behaviour, or edge cases introduced by schema evolution. Once the transformation completes, the Silver table reflects the latest known state of the domain, ready for immediate use by downstream consumers.
- TASK reads from STREAM
- Filter to
IsCurrent = TRUE - Clean + simplify schema
- Deduplicate
- Materialise as table
- (Optional) Cluster for performance
Gold (Business Models / Data Products)
From here, Gold-layer models and data products build on Silver tables rather than Bronze history. Domain-level views, KPIs, regulatory aggregates, dashboards, and machine learning features all operate against clean, current-state data, while the full historical record remains preserved and accessible in Bronze for audit, investigation, and remediation.
This pipeline runs continuously and predictably. Changes flow forward; history accumulates safely behind the scenes. The result is an architecture that satisfies both regulatory depth and analytical simplicity without forcing either concern to dominate the design.
- Join Silver tables
- Build domain views: Customers, Products, Accounts
- Compute KPIs
- Feed dashboards, models, and regulatory reporting
5. Why This Pattern Works So Well in Snowflake
Not all platforms support this approach equally well. Here, the focus shifts from mechanics to outcomes, examining why this design consistently performs well in Snowflake environments, particularly at scale and under regulatory scrutiny. The section ties platform behaviour to operational, governance, and cost benefits observed in mature implementations.
The effectiveness of this Bronze-to-Silver pattern is not accidental. It emerges from a close alignment between Snowflake’s execution model and the operational realities of large-scale, regulated data platforms. Each layer plays a clearly defined role, and Snowflake’s native capabilities reinforce that separation rather than fighting it.
5.1 Efficient Incremental Processing
STREAMS ensure no full scans.
TASKS ensure the pipeline is automated and fault-tolerant.
At scale, efficiency is determined not by how fast a platform can scan data, but by how often it avoids scanning data altogether. By combining Streams with Tasks, this pattern ensures that only newly changed records drive downstream processing.
Rather than repeatedly evaluating the full SCD2 history to determine the current state, Silver refreshes are driven entirely by deltas emitted from the Bronze layer. This keeps execution time bounded, reduces warehouse consumption, and ensures that performance remains stable even as historical depth increases. Incremental processing becomes the default, not an optimisation.
5.2 Simplified Governance
Bronze retains lineage; Silver provides clean, governed interfaces.
This architecture draws a clear boundary between historical truth and analytical usability. The Bronze layer preserves full lineage, versioning, and effective dating, satisfying audit, regulatory, and investigative requirements. The Silver layer, by contrast, exposes a curated, stable interface designed explicitly for consumption.
This separation simplifies governance by reducing the number of consumers who need to understand SCD2 semantics. Controls, validation rules, and lineage checks remain concentrated in Bronze, while Silver tables can be governed as domain data products with well-defined ownership, contracts, and quality expectations.
5.3 Strong Alignment with Data Mesh
Domain teams can own their Silver tables without needing to understand SCD2 complexities.
In a Data Mesh context, domain teams are accountable for the data products they expose, not for the ingestion mechanics that feed them. This pattern supports that model cleanly. Domains can own Silver tables that reflect their current operational reality without being burdened by historical modelling complexity.
Because the Bronze layer absorbs SCD2 logic centrally, Silver tables can be treated as stable, shareable assets. This enables decentralised ownership while preserving consistency in how history is captured, interpreted, and retained across the platform.
5.4 Optimal Cost Control
Silver can live in a lower-cost warehouse or run less frequently.
Bronze can be tiered or archived while remaining queryable.
Cost efficiency in Snowflake is driven by workload isolation and proportional compute usage. By limiting Silver processing to incremental changes, this pattern avoids unnecessary warehouse utilisation and allows refresh cadence to be tuned independently of ingestion frequency.
Silver transformations can run on smaller or lower-priority warehouses, while Bronze ingestion and SCD2 maintenance remain isolated. Historical data can be tiered or archived without impacting analytical performance, ensuring that long retention periods—common in Financial Services—do not translate into uncontrolled cost growth.
5.5 Predictable, User-Friendly Analytics
Most downstream consumers don’t need or want history.
Silver gives them one row per entity, simple, stable, fast.
Most downstream consumers do not need temporal context; they need clarity. By presenting one row per entity with a simplified schema, the Silver layer removes the cognitive and technical overhead associated with SCD2 querying.
This leads to more predictable analytics: simpler joins, fewer errors, consistent metrics, and faster query performance. BI tools, feature engineering pipelines, and reporting workloads all benefit from a data shape that matches their expectations, while historical complexity remains safely abstracted away.
5.6 Operational Resilience and Recoverability
Finally, this pattern improves day-to-day operational resilience. Because Bronze retains complete history and Snowflake provides Time Travel, Silver tables can be rebuilt deterministically in the event of logic errors, upstream corrections, or reprocessing requirements.
Failures are contained rather than catastrophic. Pipelines can be rerun from known-good states, investigations can trace issues back to their origin, and remediation does not require ad hoc data repair. This predictability is especially valuable in regulated environments, where explaining and controlling recovery are as important as performance.
5.7 Operational Monitoring and Observability
Snowflake provides native visibility into the health of both Streams and Tasks. Teams commonly monitor stream freshness using metadata such as SYSTEM$STREAM_HAS_DATA and review task execution, failures, and runtimes via TASK_HISTORY. These system views make it straightforward to detect stalled pipelines, delayed refreshes, or upstream ingestion issues without external orchestration tooling.
5.8 Alternative Approach: Using Dynamic Tables for the Silver Layer
In newer Snowflake deployments, Dynamic Tables provide a declarative alternative for building and maintaining current-state Silver tables. Rather than explicitly wiring Streams and Tasks, Dynamic Tables allow teams to define what the Silver layer should represent, while Snowflake manages incremental refresh and dependency tracking automatically.
For current-state use cases, a Silver table can often be expressed as a simple query over the SCD2 Bronze layer, for example selecting only the active version per business key. Snowflake then incrementally maintains the result set as Bronze data changes, reducing operational overhead and simplifying pipeline management.
Dynamic Tables can also be applied directly to SCD2-style logic in some scenarios, particularly where source data arrives as clean CDC events and historical semantics are straightforward. Snowflake documentation and community patterns increasingly demonstrate Dynamic Tables being used for both current-state materialisation and, in limited cases, simplified SCD2 handling.
That said, Streams and Tasks remain the preferred approach where:
- Custom CDC logic is required
- Complex merge conditions or conditional deletes are involved
- Explicit control over execution timing is needed
- Edge cases such as replays, late-arriving data, or regulatory remediation must be handled deterministically
In practice, many mature Snowflake platforms adopt a hybrid model: Dynamic Tables for simpler Silver transformations, and Streams/Tasks for domains with more complex ingestion, compliance, or operational requirements.
6. Summary: Turning Historical Truth into Analytical Clarity
The article concludes by reinforcing the central architectural principle: history and usability do not need to compete. This summary distils the key ideas into a single narrative, showing how SCD2 Bronze layers and non-SCD Silver layers work together to deliver both regulatory confidence and analytical simplicity in modern Snowflake-based data platforms.
In Snowflake, moving from an SCD2 Bronze layer to a non-SCD Silver layer provides a powerful, elegant architectural pattern.
The Bronze layer captures every historical detail for audit, compliance, and lineage.
The Silver layer exposes clean, current-state data for analytics, BI, ML, and downstream Data Products.
Snowflake’s native features, Streams, Tasks, micro-partitioning, clustering, Time Travel, and cost-efficient storage, make this workflow straightforward, scalable, and fully aligned with both enterprise and regulatory needs.
This pattern is now considered a best-practice approach in UK Financial Services and other highly regulated industries.