Schema browser and history
The sidebar has three tabs: Schema, History and Extensions (表结构, 查询历史 and 扩展 in Chinese). The button at the left of the title bar, or ⌘B, hides the sidebar and brings it back; the button stays in the same place either way. Whether the sidebar is hidden is remembered.
The schema tree
From top to bottom, the tree shows Local files, Dashboards, and S3 as small grey section headings, followed by your databases as bold rows:
- Local files — the data files you have registered, each named by its view, with its row count. Its children are the view's columns.
- The file name appears beside the view name only when the two differ (
sales_2fromsales.csv). - The folder appears when two files share a view name.
- Hover a row for the full path.
- The file name appears beside the view name only when the two differ (
- Dashboards — the
.dashdashboards you have opened recently, sorted by name so a row stays put when you click it.- Click one to reopen it as a tab, the way you would a file.
- Two dashboards with the same name show their folder beside it. One file reached by two spellings of its path (
E:\ProjandE:\proj, or a relative and an absolute path) is one entry, and opens one tab. - The × on hover takes it off the list, leaving its files and any open tab alone.
- An entry whose path no longer exists is dropped from the list.
- S3 — present once S3 is configured. Loads lazily.
- Each database, then its schemas, then tables and views, then columns. The database the window opened comes first; databases you attached beside it follow, marked
read-onlywhen attached that way.
Tables show estimated row counts; views do not. Column entries show DuckDB data types. The system database and the information_schema, pg_catalog, and system schemas are hidden.
The search box over the tree (Search tables and columns) keeps only the rows whose names contain what you type, ignoring case, and the rows above them. A table whose name matches keeps all its columns; a table kept for a matching column opens to show it. Clear the box to get the whole tree back.
Databases
The open database comes first, then each attached database as a group of its own, with the number of tables beside its name.
- An attached database shows even when it is empty. The open database is left out while it has no tables, which is how a fresh in-memory session starts.
- A muted hint beside the name says read-only, and the file type when it is not DuckDB (sqlite).
- Hover the name for the database file's path.
Right-click a database to make it the default or to detach it — see Right-click menu.
The refresh button beside the tabs (Refresh schema) reloads the catalog and the list of registered files.
Generating a SELECT
All the clicks below replace the entire buffer of the active tab — they do not insert at the cursor. The same is true of clicking a history entry. Save anything you care about before clicking around.
These fill the active editor when clicked:
| Click | Generated SQL |
|---|---|
| A table's play button | SELECT * FROM db.schema.table LIMIT 100; |
| A column's checkbox, or its name | SELECT col FROM db.schema.table LIMIT 100; |
| More columns of the same table | SELECT a, b FROM db.schema.table LIMIT 100; |
| An S3 object that is a data file | SELECT * FROM 's3://bucket/key' LIMIT 100; |
Each column, of a table, a view or a local file, has a checkbox. Ticking columns, or clicking their names, which ticks them, builds the SELECT from the ticked ones, in the table's column order rather than the order you ticked them. Unticking the last one gives SELECT *. The ticks belong to one table: ticking a column of another table starts over there.
The generated SQL spans three lines (SELECT …, FROM …, LIMIT 100;). Table names are written as short as the current default database and schema allow: orders for a table in the default schema, main.orders for another schema of the same database, and database.schema.table otherwise. After Use as default database on snap, a preview of one of its tables reads FROM orders. Until the first query has run, names are fully qualified.
A name is double-quoted only when it contains characters other than letters, digits and underscores.
Right-click menu
Every command a row's hover buttons offer is also on its right-click menu, so you can find the command without hovering:
| Row | Menu |
|---|---|
| Table or view | Generate SELECT query, Column overview, Copy name, Copy table info |
| Column | Generate SELECT query, Copy name, Change data type… (table columns only) |
| Attached database | Use as default database, Detach database |
| S3 bucket list | Refresh buckets |
| Recent dashboard | Remove from list |
| Local file | Generate SELECT query, Column overview, Copy name, Copy table info, Remove from local files |
Copy name copies the bare name — the table, column or view name alone, not qualified with its database and schema, and not quoted.
Copy table info copies the whole table as Markdown, ready to paste into a chat, an issue or an AI agent's prompt — the name a query uses, what it is, its size, and every column with its type:
memory.main.orders (table, ~224 rows, 3 columns)
| column | type |
|---|---|
| date | DATE |
| channel | VARCHAR |
| revenue | DOUBLE |Column overview replaces the active editor's text with FROM <table>;, runs it, and opens the results panel on its Overview tab, which summarizes every column of the whole table: nulls, distinct values, range and a small chart of its values. See Column overview.
Use as default database runs USE on that database, so table names without a database resolve there, and generated queries get shorter (see above). It is not offered on the database that is already the default.
Detach database detaches an attached database and forgets it, so it is not attached again next time. If it was the default, the session moves to another database first. The file is not touched. The open database itself cannot be detached, so its menu has no such item. More in Attached databases.
Altering a column type
A column row offers a type action (not available on view columns, so attached CSV and Parquet columns cannot be retyped). It opens a free-text dialog pre-filled with the current type and runs:
ALTER TABLE db.schema.table ALTER COLUMN col SET DATA TYPE <what you typed>The table name is always fully qualified here, and the column name is quoted only when it needs to be.
There is no picker and no validation list — any DuckDB type string works, including parameterised ones like DECIMAL(10,2). An invalid type comes back as an error notification. Success reloads the catalog.
Renaming and dropping columns, and editing column comments, are not available.
Removing a registered file
The × on a file row asks for confirmation, then drops the view and forgets the registration. The file on disk is not touched.
To remove several registrations together, select their rows under Local files:
- ⌘-click on macOS or Ctrl-click on Windows/Linux adds or removes one file from the selection.
- Shift-click selects a consecutive range.
- Click × on a selected file, or use its right-click removal action, to confirm removing the selected registrations. The menu shows how many files will be removed.
This removes the views and registrations, leaving the original files on disk. Selecting files this way does not select database tables or dashboard filters.
Extensions
The Extensions tab lists every DuckDB extension the engine knows of: loaded ones first, then installed ones, then the rest, each group by name.
Each row shows:
- the extension's name and a status tag: Loaded, Installed or Not installed;
- DuckDB's one-line description of it;
- its version and where it came from: built in, or the repository it was installed from (
core,community, or a URL).
What the statuses mean:
| Status | Meaning |
|---|---|
| Loaded | Active in the current connection: its functions, readers and types work in queries now |
| Installed | Downloaded to this machine, but not loaded in this connection |
| Not installed | Known to DuckDB, but not on this machine yet |
Built in extensions are compiled into DuckLocal — parquet and json among them, both loaded from the start. They are never installed or updated.
A row offers the actions that apply to it:
| Button | Shown when | Runs |
|---|---|---|
| Install | Not installed | INSTALL name |
| Load | Installed, not loaded | LOAD name |
| Update | Installed from a repository | UPDATE EXTENSIONS (name) |
- Install and Update download from DuckDB's extension repository, so they need the network. Load reads the installed file and does not.
- Installing does not load. Click Load afterwards, or run
LOAD name. - An installed extension stays installed: it is a file on disk, in DuckDB's own extension folder. Loading lasts only for the current connection.
- That folder is per DuckDB release (
~/.duckdb/extensions/v2.0.0/…). When an update moves DuckLocal to a new DuckDB release, as 0.3.0 did with DuckDB 2.0, the extensions you had show as Not installed until you install them again. - One action runs at a time; the other buttons are disabled meanwhile. A notification says Installed …, Loaded … or Updated …, or why it failed.
- After a load or an update, the schema tree is reloaded, since an extension can bring tables and functions with it.
The list is read from duckdb_extensions() each time the tab opens, after each action, when the connection changes while the tab is open, and when you click the refresh button beside the tabs (Refresh extensions). So it also shows an extension loaded another way — by a LOAD typed in a query tab, or by DuckDB on its own.
Since v0.2.1, neither the window nor the CLI automatically downloads a missing extension when a query needs it. Install it explicitly in Extensions or with INSTALL name. Extensions already installed on this machine can still load automatically.
Open the DuckDB UI
The DuckDB UI — DuckDB's own browser notebook, built by MotherDuck — is an extension like any other, so it runs inside DuckLocal too:
On the Extensions tab, click Install on the
uirow, then Load.In a query tab, run:
sqlCALL start_ui();Your browser opens the UI at
http://localhost:4213. To start the server without opening a browser, runCALL start_ui_server();instead.

The UI runs on the DuckDB instance it was started from, which here is DuckLocal's. Some things to know:
- It needs the network. Installing
uidownloads it, like any extension. And each time it starts, the extension's local server fetches the UI's own files fromhttps://ui.duckdb.org. Your queries and data still run locally. - It lives as long as DuckLocal does. Quitting DuckLocal closes its DuckDB instance, and the server with it.
CALL stop_ui_server();stops it sooner. - Notebooks are saved by the extension, not by DuckLocal, in
~/.duckdb/extension_data/ui/. DuckLocal's query history does not include what you run in the UI. - It cannot run directly on a read-only database. Attach that database from a notebook with
ATTACH '…' (READ_ONLY)instead.
DuckDB UI vs DuckLocal compares the two and covers when to use which.
Query history
Every run is recorded — successes and failures alike — with a local-time timestamp, duration in milliseconds, row count (or affected-row count for DML), and the error text if it failed. Failed entries are shown in red with a Failed tag.
The list shows the newest 200 entries. Clicking a row refills the active editor with that SQL and focuses it, replacing whatever was there.
There is no retention policy and no pruning: the history table grows without bound, and the UI simply shows the most recent 200. There is also no search, no filter, no export, and no way to delete an entry from the interface.
History is stored in DuckLocal's own database file, not in the database you have open, so it survives switching databases and losing your workspace. See Settings and app data for where it lives.
