> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lancedb.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Using Namespaces

> Use LanceDB's namespace-aware table and catalog APIs in Python, TypeScript, and Rust.

As your table organization needs grow over time and your projects become more complex, you can use namespaces to organize your tables in a way that reflects your business domains, teams, or environments.

As described in the [Namespaces and Catalog Model](https://docs.lancedb.com/namespaces.md) section, namespaces are LanceDB's way of generalizing catalog specs, providing developers a clean way to manage hierarchical organization of tables in the catalog. The SDKs treat a namespace as a path and can use it for table resolution when you use LanceDB outside the root namespace.

## Table operations with namespace paths

Let's imagine a scenario where your table management needs have evolved, and you now have the following multi-level structure to organize your tables outside the root namespace.

```
./local_lancedb (root)
└── prod
    └── search
        └── user   (table)
            └── data   (table)
    └── recommendations
        └── user   (table)
            └── data   (data)
```

Below, we show how you would express table operations within that namespace. Each item in the namespace
list (`["prod", "search"]`) represents a level in the namespace hierarchy, and the table name is
specified when you create, open, list, or drop it.

The SDK methods expose the namespace path in the idiom of each language:

* Python: pass `namespace_path=["prod", "search"]` to table operations.
* Rust: call builder methods such as `.namespace(vec!["prod".to_string(), "search".to_string()])`.
* TypeScript: pass a `namespacePath` array, for example `await db.openTable("user", ["prod", "search"])`.

import lancedb

db = lancedb.connect\_namespace("dir", \{"root": "./local\_lancedb"})

\# Create namespace tree: prod/search
db.create\_namespace(\["prod"], mode="exist\_ok")
db.create\_namespace(\["prod", "search"], mode="exist\_ok")
db.create\_namespace(\["prod", "recommendations"], mode="exist\_ok")

db.create\_table(
&#x20;   "user",
&#x20;   data=\[\{"id": 1, "vector": \[0.1, 0.2], "name": "alice"}],
&#x20;   namespace\_path=\["prod", "search"],
&#x20;   mode="create",  # use "overwrite" only if you want to replace existing table
)

db.create\_table(
&#x20;   "user",
&#x20;   data=\[\{"id": 2, "vector": \[0.3, 0.4], "name": "bob"}],
&#x20;   namespace\_path=\["prod", "recommendations"],
&#x20;   mode="create",  # use "overwrite" only if you want to replace existing table
)

\# Verify
print(db.list\_namespaces())  # \['prod']
print(db.list\_namespaces(namespace\_path=\["prod"]))  # \['recommendations', 'search']
print(db.list\_tables(namespace\_path=\["prod", "search"]))  # \['user']
print(db.list\_tables(namespace\_path=\["prod", "recommendations"]))  # \['user']


const db = await lancedb.connectNamespace("dir", \{ root: "./local\_lancedb" });

// Create namespace tree: prod/search and prod/recommendations
await db.createNamespace(\["prod"], \{ mode: "exist\_ok" });
await db.createNamespace(\["prod", "search"], \{ mode: "exist\_ok" });
await db.createNamespace(\["prod", "recommendations"], \{ mode: "exist\_ok" });

await db.createTable(
&#x20; "user",
&#x20; \[\{ id: 1, vector: \[0.1, 0.2], name: "alice" }],
&#x20; \["prod", "search"],
&#x20; \{ mode: "create" }, // use "overwrite" only if you want to replace existing table
);

await db.createTable(
&#x20; "user",
&#x20; \[\{ id: 2, vector: \[0.3, 0.4], name: "bob" }],
&#x20; \["prod", "recommendations"],
&#x20; \{ mode: "create" },
);

// Verify
console.log((await db.listNamespaces()).namespaces); // \["prod"]
console.log((await db.listNamespaces(\["prod"])).namespaces); // \["recommendations", "search"]
console.log(await db.tableNames(\["prod", "search"])); // \["user"]
console.log(await db.tableNames(\["prod", "recommendations"])); // \["user"]


let conn = connect(uri).execute().await?;
let search\_namespace = vec!\["prod".to\_string(), "search".to\_string()];
let recommendations\_namespace = vec!\["prod".to\_string(), "recommendations".to\_string()];

let schema = std::sync::Arc::new(arrow\_schema::Schema::new(vec!\[
&#x20;   arrow\_schema::Field::new("id", arrow\_schema::DataType::Int64, false),
]));

conn.create\_empty\_table("user", schema.clone())
&#x20;   .namespace(search\_namespace.clone())
&#x20;   .execute()
&#x20;   .await?;

conn.create\_empty\_table("user", schema)
&#x20;   .namespace(recommendations\_namespace.clone())
&#x20;   .execute()
&#x20;   .await?;

let search\_table\_names = conn
&#x20;   .table\_names()
&#x20;   .namespace(search\_namespace)
&#x20;   .execute()
&#x20;   .await?;
let recommendation\_table\_names = conn
&#x20;   .table\_names()
&#x20;   .namespace(recommendations\_namespace)
&#x20;   .execute()
&#x20;   .await?;

println!("\{search\_table\_names:?}"); // \["user"]
println!("\{recommendation\_table\_names:?}"); // \["user"]


> [!NOTE]
>
> Using namespaces is **optional** in LanceDB, and most basic use cases do not require to work with them.
> An empty namespace (`[]`), which is the default, means "root namespace", and the data will be stored in
> the `data/` directory under the specified root path.

## Namespace management APIs

You can open/create/drop tables inside a namespace path (like `["prod", "search"]`).
All three SDKs expose namespace lifecycle operations directly.
In Python, use `lancedb.connect_namespace(...)` when calling namespace lifecycle methods such as
`create_namespace`, `list_namespaces`, `describe_namespace`, and `drop_namespace`.
In TypeScript, use `lancedb.connectNamespace(...)` and call `createNamespace`, `listNamespaces`,
`describeNamespace`, and `dropNamespace` on the returned `Connection`.
In Rust, use `lancedb::connect_namespace(...)` and call `create_namespace`, `list_namespaces`,
and `drop_namespace`.

import lancedb

db = lancedb.connect\_namespace("dir", \{"root": "./local\_lancedb"})
namespace = \["prod", "search"]

db.create\_namespace(\["prod"])
db.create\_namespace(\["prod", "search"])

child\_namespaces = db.list\_namespaces(namespace\_path=\["prod"]).namespaces
print(f"Child namespaces under \{namespace}: \{child\_namespaces}")
\# Child namespaces under \['prod', 'search']: \['search']

metadata = db.describe\_namespace(\["prod", "search"])
print(f"Metadata for namespace \{namespace}: \{metadata}")
\# Metadata for namespace \['prod', 'search']: properties=None

db.drop\_namespace(\["prod", "search"], mode="skip")
db.drop\_namespace(\["prod"], mode="skip")


const db = await lancedb.connectNamespace("dir", \{ root: "./local\_lancedb" });
const namespace = \["prod", "search"];

await db.createNamespace(\["prod"]);
await db.createNamespace(\["prod", "search"]);

const childNamespaces = (await db.listNamespaces(\["prod"])).namespaces;
console.log(\`Child namespaces under \$\{JSON.stringify(namespace)}:\`, childNamespaces);
// Child namespaces under \["prod","search"]: \[ 'search' ]

const metadata = await db.describeNamespace(\["prod", "search"]);
console.log(\`Metadata for namespace \$\{JSON.stringify(namespace)}:\`, metadata);

await db.dropNamespace(\["prod", "search"], \{ mode: "skip" });
await db.dropNamespace(\["prod"], \{ mode: "skip" });


let mut properties = std::collections::HashMap::new();
properties.insert("root".to\_string(), "./local\_lancedb".to\_string());
let db = lancedb::connect\_namespace("dir", properties).execute().await?;
let namespace = vec!\["prod".to\_string(), "search".to\_string()];

db.create\_namespace(lance\_namespace::models::CreateNamespaceRequest \{
&#x20;   id: Some(vec!\["prod".to\_string()]),
&#x20;   ..Default::default()
})
.await?;
db.create\_namespace(lance\_namespace::models::CreateNamespaceRequest \{
&#x20;   id: Some(namespace.clone()),
&#x20;   ..Default::default()
})
.await?;

let child\_namespaces = db
&#x20;   .list\_namespaces(lance\_namespace::models::ListNamespacesRequest \{
&#x20;       id: Some(vec!\["prod".to\_string()]),
&#x20;       ..Default::default()
&#x20;   })
&#x20;   .await?;
println!(
&#x20;   "Child namespaces under \{:?}: \{:?}",
&#x20;   namespace, child\_namespaces
);
// Child namespaces under \["prod", "search"]: \["search"]

db.drop\_namespace(lance\_namespace::models::DropNamespaceRequest \{
&#x20;   id: Some(namespace.clone()),
&#x20;   ..Default::default()
})
.await?;
db.drop\_namespace(lance\_namespace::models::DropNamespaceRequest \{
&#x20;   id: Some(vec!\["prod".to\_string()]),
&#x20;   ..Default::default()
})
.await?;


Namespace creation and deletion have modes that control what happens when the target already exists,
doesn't exist, or contains data:

* Create mode: `create` fails if the namespace already exists, `exist_ok` keeps the existing namespace, and `overwrite` replaces it.
* Drop mode: `fail` reports an error when the namespace doesn't exist, and `skip` treats a missing namespace as a successful no-op.
* Drop behavior: `restrict` keeps non-empty namespaces from being dropped, and `cascade` drops child namespaces and tables first.

Namespace path components can't be empty. Each component can contain only letters, numbers,
underscores, hyphens, and periods.

Listing APIs return the immediate children of the requested namespace path. Use `limit` with the
returned `page_token` to page through large catalogs; pass an empty namespace path (`[]`) when you
want to list from the root namespace.

## Namespaces in LanceDB Enterprise

In LanceDB Enterprise deployments, configure namespace-backed federated databases in a TOML file under your deployment's `config` directory.
LanceDB Enterprise supports both directory-based (`ns_impl = "dir"`) and REST-based (`ns_impl = "rest"`) namespace implementations.
The example below shows how to configure a directory-based namespace implementation in LanceDB Enterprise.

```toml theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
# Federated database configuration for DirectoryNamespace
# This example uses minio storage
[federated_dbs.federated_dir_test]
ns_impl = "dir"
root = "s3://<your-deployment>/<your-dir>"
"storage.region" = "us-east-1"
"storage.endpoint" = "http://localhost:9000"
"storage.access_key_id" = "minioadmin"
"storage.secret_access_key" = "minioadmin"
"storage.allow_http" = "true"
# Far future expiration (year 2100)
"storage.expires_at_millis" = "4102444800000"
```

The example above uses MinIO, but the same approach applies to other cloud object storage platforms based on your deployment.

For REST-based namespace servers, you can specify the namespace implementation as `"rest"` with forwarding prefixed headers
for authentication and context propagation.

```toml theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
[federated_dbs.federated_rest_test]
ns_impl = "rest"
uri = "http://<your_org>.internal.catalog.com"
forward_header_prefixes = ["X-forward"]
```

With `forward_header_prefixes = ["X-forward"]`, any incoming header starting with `X-forward` is forwarded to
`http://<your_org>.internal.catalog.com`. This is useful for auth propagation, for example sending
`X-forward-authorization: Bearer xxxx`.

For the LanceDB REST API itself, requests use `x-api-key` for API-key authentication. If your endpoint
serves more than one database, LanceDB can also use headers such as `x-lancedb-database` or
`x-lancedb-database-prefix` to route the request to the right database context.

## Related references

* [Client SDK API references](https://docs.lancedb.com/api-reference.md)
* [REST API Reference](https://docs.lancedb.com/api-reference/rest.md)
* [Namespaces and the Catalog Model](https://docs.lancedb.com/namespaces.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.