Most teams don't argue about whether to adopt Medallion Architecture. Bronze, Silver, Gold is an easy pitch, and it maps cleanly onto a whiteboard. The argument starts once someone tries to build it. Who's allowed to query what? Does a Gold table get to read straight from Bronze? What happens when another team asks for access to one Silver table because it's "just easier" that way?
Treat Databases as Data Products
What Bronze, Silver, and Gold Actually Mean
Database Design Rules on Snowflake
The three-layer picture doesn’t answer any of that. It has to be answered by database design decisions that most Medallion write-ups skip entirely. Below are the rules we ended up writing down after running into the same disagreements more than once, applied specifically to Snowflake.
Treat Databases as Data Products
Before getting into the layers, one ground rule matters more than the rest: Medallion works best on top of a Data Lake House, combined with some Data Mesh thinking, and it only holds together if the databases underneath follow Domain-Driven Design principles.
In practice, that means two things. A database should be treated as a dedicated Data Product — a persistence layer for one bounded context, similar to how a microservice owns its own data. It should encapsulate a specific subdomain, enforce that subdomain’s business rules at the data level, and keep tight control over how other systems integrate with it. And within a bounded context, the data model should be split into cohesive sub-models, each with its own database object rather than one large shared schema.
It’s tempting to skip this part and just bolt three schemas onto an existing database. Without the bounded-context thinking behind it, though, Medallion ends up being three folders on top of the same shared, ownerless warehouse you had before.
What Bronze, Silver, and Gold Actually Mean
The three layers get described often enough that it’s easy to gloss over what each one is actually for, and that’s usually where implementation decisions go wrong.
Bronze is the landing zone. Data pulled in from external systems, kept close to its original, raw form, with minimal parsing applied.
Silver is where the real cleanup happens: null handling, error correction, validation against business rules, standardizing formats, deduplication, and sometimes normalization. What comes out the other side should be consistent and trustworthy, even if it isn’t organized yet for any particular audience.
Gold is built for consumption — aggregated, business-specific, usually modeled as star schemas (facts and dimensions) for read performance. This is meant to be the “single version of the truth” for a domain: not just clean data, but data shaped around how people actually query it, whether that’s a dashboard, a report, or a feature for a model.
Database Design Rules on Snowflake
On Snowflake, one of the most balanced approaches is to introduce the three layers as three schemas: bronze, silver, gold. Each one gets tagged to its layer with medallion:<layer value>. If a database ends up with a lot of tables sharing the same data product, it’s fine to spread a layer across multiple schemas instead of forcing everything into one — just make sure each of them carries the right tag, and every table in a schema actually belongs to that layer.
The part that turns this from a diagram into something enforceable is access control:
- Data consumers get read access to gold That’s built into the role, not a convention people are expected to remember.
- Bronze doesn’t reference Silver, and Silver doesn’t reference Gold. Upstream layers stay unaware of what’s downstream from them.
- A table or ELT job can use its own layer or anything upstream of it — Gold can read Silver or Gold, Silver can read Silver or Bronze.

Data moves downstream through the layers one direction at a time; only Gold gets queried directly by consumers.
None of this is mandatory for every database. If something is static and doesn’t need processing, it’s fine to skip Medallion until there’s an actual reason to introduce it. A database with a handful of tables can just use a gold or public schema and move on.
Where the Data Comes From
Transactional integrations that belong to a bounded context should generally start in Bronze and move through the layers the normal way, regardless of whether the source is internal or third-party.
Reference or Master data is a different case — dimensions and similar tables are usually owned by Back Office or another application. That kind of data should land in its own database (or a side schema if a full database is overkill) and stay queryable from any layer. It’s closer to infrastructure than to a Medallion layer: always accessible, and treated as an immutable mirror kept current by whatever replication process runs behind it.
Data owned by an external bounded context follows a similar pattern — its own database, replicated through Snowflake Listing/Share or a custom pipeline, queryable from inside the current bounded context. More on that in the fourth edge case below.
The Situations That Don’t Fit Neatly
The rules above hold up fine until an actual request comes in that doesn’t match any of them cleanly. A few of these show up often enough to be worth spelling out.
Someone wants direct access to a Silver table.
Since consumers don’t get Silver access, the fix is a proxy view in Gold with the same shape: CREATE VIEW gold.xxx AS SELECT * FROM silver.xxx. It also happens to give you a safe place to rename a field or add a computed column without touching the underlying table.

Gold mirrors Silver’s contract through a view, so consumers never touch Silver directly.
A Gold table depends on something in Bronze.
Querying Bronze directly is fine if a proxy view genuinely isn’t practical, but the better pattern is a view in Silver that exposes the Bronze data, so Gold never has to reach past Silver.
You need a table from another database in the same bounded context.
The one non-negotiable requirement is a stable, public interface on the source table. From there it depends on where that database lives: attach it as a replica through Listing or Internal Marketplace if it’s in another Snowflake account, or stand up a dedicated, kept-in-sync database if the source isn’t on Snowflake at all. Client-facing queries are usually fine as long as privileges and visibility line up; ELT/ETL logic just follows the same rules as any other reference-data integration.
You need a table from a completely different bounded context.
Client-facing access again isn’t really an issue. ELT/ETL logic is the harder case, and there isn’t a clean answer, just two options with different trade-offs.
- The pragmatic route treats it like a microservice call — let Silver or Gold in the current database reference the external database directly. It works, but it blurs the bounded-context boundary and carries the risk that comes with that.
- The more disciplined route moves the workflow and the table it depends on into a dedicated database built for cross-context access. More setup work, but it avoids coupling your main database to someone else’s.
Naming and Environments
Every database that isn’t an external replica needs its own instance per environment, with the environment baked into the name.
Naming conventions are worth deciding early rather than letting them drift. One pattern that works reasonably well is <bounded_context>_<database_name>_<env> — for example bu_dlh_prod, malv_dlh_stage, malv_bo_prod, malv_bo_stage, where dlh stands for Data Lake House and bo for Back Office. External databases from other bounded contexts can follow the same convention, e.g. media_dlh_prod. The exact pattern matters less than everyone actually sticking to it.
What This Costs You
The upside is real: granular, clearly owned databases that are easy to combine, retire, or extend independently, and that hold up reasonably well against DDD and SOLID thinking.
The downside is real too. Every field change has to move through the whole chain from Bronze to Gold, and any proxy view built on a changed table needs to be rebuilt. Push the granularity too far, and you end up spending more time maintaining database objects than you save in flexibility.
A few of these rules are intentionally strict, and it’s worth being upfront about where teams commonly bend them:
- Gold-only external access is the default, but exposing a Silver table directly is sometimes reasonable, as long as everyone involved understands the trade-off.
- Proxy views between Bronze and Gold add overhead that isn’t always worth it. If a Bronze table is final and needs no further processing, querying it directly from Gold is a fair compromise.
- Medallion and non-Medallion tables can live in the same database, provided they genuinely belong to the same bounded context.
- Large databases don’t have to cram every table into one schema per layer, splitting Silver or Gold across multiple tagged schemas is fine, as long as the tags are correct.
The Bottom Line
Medallion Architecture by itself is three labels on a diagram. What actually makes it work on Snowflake is everything underneath the labels: treating every database as an owned, bounded-context Data Product, enforcing Bronze-Silver-Gold access through real schema tags and role privileges instead of tribal knowledge. It is also important to have a pre-agreed pattern (proxy views, replica databases, naming conventions) for the requests that don’t fit the clean version of the model.
None of the individual pieces are exotic. A tagging convention, a read-only role scoped to Gold, a view that mirrors a contract instead of exposing a table, each one is small on its own. What they add up to is a warehouse that grows by adding and retiring bounded contexts, instead of getting harder to change every time another team needs data from it.
The trade-off is real, and worth restating plainly: more schemas, more views, and more discipline around every field change. For one small team with a handful of tables, that overhead may not be worth paying. For an organization with multiple bounded contexts that all need to share data safely, it’s the difference between a warehouse that scales and one that quietly turns back into a monolith with better branding.
None of these rules are complicated on their own. What’s hard is writing them down before the first disagreement instead of after.