Files
lancedb/docs/web/integrations/ai/vscode.mdx
T
Jack YeandClaude Sonnet 5 de95ed3f6d docs: overhaul curation, feature engineering, security and deployment guides (#4748)
A broad documentation pass across the areas LanceDB Enterprise and
Embedded
diverge on most:

**Data Curation** -- GPU Function execution, Slurm scheduling (and what
Slurm is, for readers new to it), blob late materialization as its own
page, joins, aggregation/profiling, sampling, near-duplicate detection,
chunking, distributed shuffle, and IVF-partition clustering.

**Feature Engineering** -- computed columns and materialized views,
restructured to lead with the Function-based path and show the SQL form
side by side with Python throughout; a single Auto Refresh page instead
of
duplicating scheduling details on every refresh page; adaptive
execution;
checkpointing; GPU and Slurm placement for refresh workers; a Training
Cache page for the PyTorch data loader's automatic cache benefit.

**Security & Governance** -- an Audit Log reference (schema, access,
grants), Secrets promoted to an ordinary catalog object with their own
SQL
DDL and a vending/rotation guide, and privilege-table fixes verified
against the authorization source.

**Deployment & Maintenance** -- Horizontal Scaling and OpenTelemetry
moved
into a real Deployment area; Automated Cleanup folded into Intelligent
Auto-Maintenance (every other maintenance decision already lived there);
RTE Compaction and Advanced Conflict Resolution documented in depth.

**Landing page** -- the Enterprise feature comparison table reorganized
(several redundant or stale rows removed, several new areas added), and
the
"why Enterprise" bullets replaced with ones tied to a concrete page
(Performance, Scale, Fault tolerance, Multicloud deployment, Simplify
operations) instead of vague promises.

Plus a full pass addressing lancedb-gatekeeper's review: a real
test-safety
bug (a quickstart test could silently overwrite and delete a
deployment's
own `frames` table), a fabricated SQL statement with no backing
implementation, an actual dedup-guarantee bug in `take_row_ids`, and
dozens
of documentation-accuracy fixes verified against source rather than
taken
on faith -- each either fixed, or left with an explicit note on why it
needs a feature or deployment owner's sign-off instead of being guessed
at.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_018PXMCbRH6i5w47TsjeEUMT

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-11-03 16:17:24 -08:00

306 lines
14 KiB
Plaintext

---
title: "VS Code extensions"
sidebarTitle: "VS Code"
description: "Embed LanceDB in a VS Code extension to search a workspace by meaning, with no server, and bundle and package its native binaries correctly."
keywords: ["vscode", "visual studio code", "extension", "electron", "esbuild", "vsix", "semantic search"]
---
import {
TsVscodeChunk,
TsVscodeConnect,
TsVscodeImports,
TsVscodeIndex,
TsVscodeSearch,
} from '/snippets/vscode_search.mdx';
import { TsVscodeExtension } from '/snippets/vscode_extension.mdx';
A VS Code extension runs in the *extension host*, a Node.js process, so LanceDB's TypeScript SDK
(`@lancedb/lancedb`) runs inside it like any other npm package. There's no database server to
start: the extension opens a table on local disk and queries it in-process. That makes LanceDB
a good fit for features such as semantic search over a workspace, retrieval for an AI assistant,
or a cache of embeddings that survives restarts.
The extension host differs from a plain Node.js script in three ways that trip people up:
- **Where you can write.** Relative paths resolve against the extension host's working
directory, not the workspace, and that directory may be read-only.
- **Bundling.** The default extension template bundles everything with esbuild, which can't
bundle LanceDB's native `.node` binary.
- **Packaging.** LanceDB installs a native binary for the current platform only, so a VSIX
built on one OS doesn't run on another.
This guide builds a small extension that handles all three. It indexes the Markdown files in a
workspace and searches them by meaning, using a local embedding model, so no API key is needed.
<Info>
**What you'll build**
- **LanceDB: Index Markdown in Workspace** splits every `*.md` file into paragraphs and stores
them in a LanceDB table, with embeddings from `Xenova/all-MiniLM-L6-v2` run locally through
Transformers.js.
- **LanceDB: Search Markdown** embeds your query, shows the five closest paragraphs, and opens
the one you pick.
</Info>
## Create the extension {#create-the-extension}
<Steps>
<Step title="Scaffold a TypeScript extension">
Use the official generator. Choose **New Extension (TypeScript)** and **esbuild** as the bundler.
<CodeGroup>
```bash Bash icon="terminal"
npx --package yo --package generator-code -- yo code
```
</CodeGroup>
</Step>
<Step title="Install LanceDB">
<CodeGroup>
```bash Bash icon="terminal"
npm install @lancedb/lancedb apache-arrow@18.1.0
```
</CodeGroup>
Your code imports Arrow types directly, so add `apache-arrow` as a dependency, pinned inside
LanceDB's peer dependency range (`>=15.0.0 <=18.1.0`). If the project already depends on a
newer `apache-arrow`, installing LanceDB fails with `ERESOLVE`.
LanceDB also needs `@types/node` 22 or later. The generator's template already uses a recent
version; an old one causes `Cannot find module 'node:stream'` errors.
You don't need to install `@huggingface/transformers` yourself. LanceDB pins it as an optional
dependency, and installing a different version gives your code a copy that LanceDB doesn't use.
</Step>
<Step title="Skip type checking of dependencies">
The type declarations of `apache-arrow` and the ONNX runtime used by Transformers.js refer to
browser types such as `ReadableStreamReadResult` and `HTMLCanvasElement`. The template's
`tsconfig.json` doesn't include the DOM library, so `tsc` reports errors inside `node_modules`.
Turn on `skipLibCheck`:
```json tsconfig.json icon="brackets-curly"
{
"compilerOptions": {
"skipLibCheck": true
}
}
```
</Step>
</Steps>
## Store the database in extension storage {#store-the-database-in-extension-storage}
Give LanceDB an absolute path inside the storage VS Code reserves for your extension:
- `context.storageUri`: a folder for the current workspace. It's `undefined` when no folder is
open. Use it for anything derived from the workspace, such as this index.
- `context.globalStorageUri`: a folder shared by all workspaces. Use it for things like
downloaded models.
Neither folder is guaranteed to exist, so create it before connecting. Both live outside the
user's project, so the index never shows up in their files or in version control.
Don't pass a relative path such as `lancedb.connect("data")`. It resolves against the extension
host's working directory, which isn't the workspace and may be read-only: this causes the
`Read-only file system (os error 30)` error on macOS.
Put the LanceDB code in its own module, `src/search.ts`:
<CodeBlock filename="src/search.ts" language="TypeScript" icon="square-js">
{TsVscodeImports}
</CodeBlock>
<CodeBlock filename="src/search.ts" language="TypeScript" icon="square-js">
{TsVscodeConnect}
</CodeBlock>
## Index and search {#index-and-search}
Split each file into paragraphs, and keep the line each one starts on so a result can open the
file at the right place:
<CodeBlock filename="src/search.ts" language="TypeScript" icon="square-js">
{TsVscodeChunk}
</CodeBlock>
Create the table with LanceDB's built-in `huggingface` [embedding function](/embedding/quickstart).
Because the `text` column is declared as the function's source field, LanceDB computes the
`vector` column for you as the rows are written:
<CodeBlock filename="src/search.ts" language="TypeScript" icon="square-js">
{TsVscodeIndex}
</CodeBlock>
The table remembers its embedding function, so you can search it with plain text after VS Code
restarts:
<CodeBlock filename="src/search.ts" language="TypeScript" icon="square-js">
{TsVscodeSearch}
</CodeBlock>
`mode: "overwrite"` rebuilds the index each time, which is fine for a few thousand paragraphs.
For larger workspaces, update only the files that changed with
[`mergeInsert`](/ingestion/merge-insert).
## Wire up the commands {#wire-up-the-commands}
Declare the two commands in `package.json`:
```json package.json icon="brackets-curly"
"contributes": {
"commands": [
{
"command": "lancedbSearch.index",
"title": "Index Markdown in Workspace",
"category": "LanceDB"
},
{
"command": "lancedbSearch.search",
"title": "Search Markdown",
"category": "LanceDB"
}
]
}
```
Then register them in `src/extension.ts`:
<CodeBlock filename="src/extension.ts" language="TypeScript" icon="square-js">
{TsVscodeExtension}
</CodeBlock>
A few details in this file are specific to running inside VS Code:
- The index goes in `storageUri`, so each workspace gets its own table.
- The embedding model (about 90 MB) downloads on first use. By default Transformers.js caches it
inside `node_modules` in the installed extension, which is replaced on every update. Setting
`env.cacheDir` keeps it in global storage. Load the module with `import()`, not `require()`:
LanceDB loads the ES module build of `@huggingface/transformers`, and `require()` returns a
separate copy whose settings LanceDB never sees.
- Each paragraph is stored with its file's URI, not a path relative to a workspace folder. In a
multi-root workspace, `findFiles` searches every folder and two folders can hold the same
relative path, so only the URI opens the right file. `asRelativePath` turns it back into a
short label, which names the folder when there's more than one.
- When another extension or a test passes a query to `lancedbSearch.search`, it returns the
rows instead of opening a picker. That's how the results below were produced, with each URI
shown through `asRelativePath`.
## Sample results {#sample-results}
Here are the results of running the extension in VS Code against a small workspace of six
Markdown files that document a fictional CLI. The columns are the vector distance (lower is
closer), the file and line, and the paragraph.
```text
query: my credentials were exposed, what should I do?
33.100 docs/auth.md:5 If a token leaks, revoke it on the Tokens page and generate a replacement. Revoked tokens stop working immediately.
40.091 docs/troubleshooting.md:5 Run `acme doctor` to print diagnostics you can attach to a bug report.
42.334 CONTRIBUTING.md:3 Run `npm test` before opening a pull request. New commands need a page in docs/.
43.105 docs/auth.md:3 Acme uses personal access tokens. Create one under Settings > Tokens.
45.664 README.md:5 Install it with `npm install -g acme-cli`, then run `acme login`.
query: uploads are stuck behind the company firewall
38.420 docs/troubleshooting.md:3 If `acme sync` hangs, check that your proxy allows connections to api.acme.dev on port 443.
39.212 docs/sync.md:3 Run `acme sync` to upload changed notes. Only files modified since the last sync are sent.
40.859 docs/auth.md:5 If a token leaks, revoke it on the Tokens page and generate a replacement. Revoked tokens stop working immediately.
42.537 docs/troubleshooting.md:5 Run `acme doctor` to print diagnostics you can attach to a bug report.
45.853 CONTRIBUTING.md:3 Run `npm test` before opening a pull request. New commands need a page in docs/.
```
Neither top result shares a keyword with its query: "credentials were exposed" matches "a
token leaks", and "stuck behind the company firewall" matches "hangs … proxy". Picking a result
in the search box opens the file at that paragraph.
## Bundle with esbuild {#bundle-with-esbuild}
The template bundles your code and its dependencies into `dist/extension.js`. esbuild can't
bundle native binaries, so building with LanceDB fails with
`No loader is configured for ".node" files`. Mark the packages that load native code as
external so they're loaded from `node_modules` at runtime:
<CodeGroup>
```javascript esbuild.js icon="square-js"
external: [
"vscode",
"@lancedb/lancedb",
"@huggingface/transformers",
// LanceDB loads apache-arrow from node_modules anyway; bundling it ships a second copy.
"apache-arrow",
],
```
</CodeGroup>
External packages must be in the VSIX, but the template's `.vscodeignore` excludes
`node_modules/**`. Delete that line. `vsce` then includes your production dependencies and
leaves out the dev dependencies. If you skip this step, the packaged extension fails to
activate with `Cannot find module '@lancedb/lancedb'`, and its commands report
`command 'lancedbSearch.index' not found`.
## Package a VSIX for each platform {#package-a-vsix-for-each-platform}
npm installs LanceDB's native binary only for the machine it runs on, such as
`@lancedb/lancedb-win32-x64-msvc` on 64-bit Windows. Build one VSIX per platform, each on a
matching machine or CI runner, and publish them all. The Marketplace serves each user the right one.
<CodeGroup>
```bash Bash icon="terminal"
npx @vscode/vsce package --target win32-x64
```
</CodeGroup>
| `vsce` target | LanceDB native package |
|:--|:--|
| `win32-x64` | `@lancedb/lancedb-win32-x64-msvc` |
| `win32-arm64` | `@lancedb/lancedb-win32-arm64-msvc` |
| `linux-x64` | `@lancedb/lancedb-linux-x64-gnu` |
| `linux-arm64` | `@lancedb/lancedb-linux-arm64-gnu` |
| `alpine-x64` | `@lancedb/lancedb-linux-x64-musl` |
| `alpine-arm64` | `@lancedb/lancedb-linux-arm64-musl` |
| `darwin-arm64` | `@lancedb/lancedb-darwin-arm64` |
LanceDB doesn't publish a binary for Intel Macs (`darwin-x64`).
The table covers LanceDB's own binaries. This sample's local model also needs
`onnxruntime-node`, which Transformers.js loads when the extension activates. Its Linux binaries
link against glibc and it publishes no musl build, so the sample as written doesn't run on
Alpine, whatever `--target` you pass. To ship the `alpine-*` targets, embed with a hosted API or
use [full-text search](/search/full-text-search) instead, or build ONNX Runtime for musl yourself.
<Tip>
Native binaries make the VSIX large: the `win32-x64` build of this extension is about 200 MB.
`onnxruntime-node`, which Transformers.js uses, ships binaries for every platform. Excluding
the ones a target doesn't need brings the `win32-x64` build to about 150 MB. Keep one ignore
file per target and pass it with `--ignoreFile`:
```text .vscodeignore.win32-x64
node_modules/onnxruntime-node/bin/napi-v3/darwin/**
node_modules/onnxruntime-node/bin/napi-v3/linux/**
node_modules/onnxruntime-node/bin/napi-v3/win32/arm64/**
```
If you don't need a local model, embed text with a hosted API instead, or use
[full-text search](/search/full-text-search), which needs no model at all.
</Tip>
## Keep the extension host responsive {#keep-the-extension-host-responsive}
All extensions share one extension host, and loading the model and computing embeddings in it
can stall the others. While the sample indexes, VS Code may briefly report that the extension
host is unresponsive. That's fine for a handful of files. For a large workspace, move indexing into a
[worker thread](https://nodejs.org/api/worker_threads.html) or a child process, and index in
batches as files change instead of all at once.
## Troubleshooting {#troubleshooting}
| Error | Cause | Fix |
|:--|:--|:--|
| `Read-only file system (os error 30)` | A relative database path resolved against the extension host's working directory | Connect to an absolute path under `context.storageUri` or `context.globalStorageUri` |
| `No loader is configured for ".node" files` | esbuild tried to bundle a native binary | Mark `@lancedb/lancedb` and `@huggingface/transformers` as `external` |
| `Cannot find module '@lancedb/lancedb'`, or `command '…' not found` | The VSIX doesn't contain `node_modules` | Remove `node_modules/**` from `.vscodeignore` |
| A native module isn't found on another OS | The VSIX was built on a different platform | Package one VSIX per `--target` on a matching machine |
| `Cannot find module 'node:stream' or its corresponding type declarations` | `@types/node` is too old | Use `@types/node` 22 or later |
| `Cannot find name 'HTMLCanvasElement'` and similar errors in `node_modules` | Dependency typings refer to DOM types | Set `"skipLibCheck": true` |
| `ERESOLVE` with `peer apache-arrow@">=15.0.0 <=18.1.0"` | The project depends on a newer `apache-arrow` | Install `apache-arrow@18.1.0` |
| The model downloads again after an update | Transformers.js caches inside the extension's `node_modules` | Set `env.cacheDir` through `import("@huggingface/transformers")` |