---
title: "Materialized view"
sidebarTitle: "Materialized View"
description: "Create, open, list and drop a table whose contents are defined by a query."
icon: table
keywords: ["materialized view", "create_materialized_view", "catalog", "ddl"]
availability:
oss: available
enterprise: varies
summary: >-
Materialized views are created and managed in the embedded library. On a
deployment they are off by default and have to be enabled, and the SDK
creates them through the deployment's SQL endpoint; see
[Against a deployment](#deployment).
---
A materialized view is a table whose contents are defined by a query over
another table. The query is recorded in the view's schema, and a refresh
brings its stored rows up to date with the source.
The result is an ordinary table -- queryable, indexable, searchable, and present
in `table_names()`. Nothing about reading it is special.
This page covers creating and managing one. Keeping it current is
[Refresh a materialized view](/feature-engineering/materialized-views).
In SQL, see [`REFRESH MATERIALIZED VIEW`](/sql/dml/refresh#refresh-materialized-view) and [`SHOW MATERIALIZED VIEWS`](/sql/ddl/materialized-view#show).
## Creating one {#create}
```python Python icon="python"
view = db.create_materialized_view(
"recent_docs",
source="documents",
select=["id", "title", "embedding"],
where="created_at > '2026-01-01'",
)
```
```typescript TypeScript icon="square-js"
const view = await db.createMaterializedView("recent_docs", "documents", {
select: ["id", "title", "embedding"],
where: "created_at > '2026-01-01'",
});
```
`source` names the table it derives from. A local source does not need stable
row ids or any other storage option; an earlier deployment version may require
stable row ids (see [Against a deployment](#deployment)). `select`, `where` and `limit` record
the query -- there is no separate definition step.
## Opening, listing and dropping {#manage}
| | Python | TypeScript | SQL |
| --- | --- | --- | --- |
| create | `create_materialized_view` | `createMaterializedView` | `CREATE MATERIALIZED VIEW` |
| open | `open_materialized_view` | `openMaterializedView` | -- |
| list | `list_materialized_views` | `listMaterializedViews` | `SHOW MATERIALIZED VIEWS` |
| refresh | `refresh` | `refresh` | `REFRESH MATERIALIZED VIEW` |
| drop | `drop_table` | `dropTable` | `DROP TABLE` |
`list_materialized_views` finds views by reading every table's schema, so it
costs one open per table. `SHOW MATERIALIZED VIEWS` asks the server instead and
is cheaper on a catalog with many tables.
A view is dropped with `drop_table`, because a materialized view **is** a table.
That also means dropping one removes stored rows -- unlike dropping a
[view](/management/view), which removes only a saved query.
## Working with the view {#working}
`view.table` is the underlying table, for querying, indexing, or search.
`view.definition` is the recorded query -- select list, predicate, limit
-- which is how you check what a view contains without inferring it from the
rows. Both are properties; on an async view, the definition is read with
`await view.definition()`.
## Against a deployment {#deployment}
Enterprise `create_materialized_view` works on a
`db://` connection as well as a local one. There the SDK creates and refreshes
the view through SQL, and the work runs on the cluster rather than in your
process, so the deployment's [SQL endpoint](/basics/sql#sql-is-remote) has to be
reachable. Materialized views are off by default on a deployment and have to be
enabled there, and an earlier deployment version may require a view's source to
have stable row ids; see
[Against a deployment](/feature-engineering/materialized-views#availability).
## What to read next {#next}
How a refresh works, and what it writes.
The non-materialized counterpart, defined in SQL.