# How DBX Implements Its Schema Browser with Sidebar Search, Pinning, and Object Grouping

> Discover how DBX implements its schema browser feature leveraging a TreeNode structure SidebarLayout fuzzy search filtering pin ordering and object grouping for efficient data exploration

- Repository: [skyler/dbx](https://github.com/t8y2/dbx)
- Tags: internals
- Published: 2026-07-04

---

**DBX implements its schema browser using a hierarchical `TreeNode` structure stored in a `SidebarLayout`, with fuzzy search filtering via `filterSidebarTree()`, pin ordering through `orderPinnedFirst()`, and object grouping controlled by the `sidebarObjectDisplay` setting.**

The DBX schema browser provides a navigable sidebar for database connections, schemas, and objects. According to the t8y2/dbx source code, the implementation relies on a reactive tree model that supports real-time search, persistent pinning, and dynamic object grouping. The architecture separates concerns between tree structure definition, layout persistence, search algorithms, and visual ordering.

## Core Architecture of the DBX Schema Browser

The schema browser is built on a tree-structured sidebar that represents connections, databases, schemas, and all object types including tables, views, and procedures.

### The Tree Model and Node Types

All sidebar items are `TreeNode` objects defined in [`apps/desktop/src/types/database.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/types/database.ts). Each node has a `type` property that can be `connection`, `database`, `schema`, `table`, `view`, or other object kinds. The hierarchy is stored in a **layout** (`SidebarLayout`) that records groups, order, and expansion state for each node.

### Sidebar Layout Persistence

The `SidebarLayout` interface persists user preferences including which nodes are expanded, the order of connections, and which items are pinned. When a connection is added, DBX builds the layout from persisted data using `reconcileLayout()` and `buildTreeNodesFromLayout()` in [`apps/desktop/src/lib/sidebar/sidebarLayout.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sidebar/sidebarLayout.ts). This ensures the sidebar state survives application restarts.

## Implementing Sidebar Search with Fuzzy Matching

When the user types in the sidebar search box, the UI filters the tree in-place while preserving relevant sub-trees.

The search implementation lives in [`apps/desktop/src/lib/sidebar/sidebarSearchTree.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sidebar/sidebarSearchTree.ts). The `filterSidebarTree()` function uses a fuzzy label matcher (`createSidebarLabelMatcher` from [`apps/desktop/src/lib/sidebar/sidebarSearch.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sidebar/sidebarSearch.ts)) to score nodes based on the query. It keeps sub-trees for node types listed in `preserveMatchedSubtreeTypes`—including connection, database, schema, table, and view—so a matching table still displays its parent schema hierarchy.

```typescript
// Filter the tree when the user types a search query
import { filterSidebarTree } from '@/lib/sidebar/sidebarSearchTree';

const query = sidebarSearchQuery.value;               // reactive value bound to <input>
const collapsed = new Set<string>(/* IDs of collapsed nodes */);
const displayed = filterSidebarTree(tree, query, collapsed);

```

The algorithm returns a pruned tree containing only matching nodes and their necessary ancestors, maintaining the hierarchical context during search.

## Pinning Connections and Groups in the Sidebar

Connections or groups that the user pins are always displayed first in the sidebar, regardless of the current layout.

The pinning logic resides in [`apps/desktop/src/lib/sidebar/sidebarLayout.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sidebar/sidebarLayout.ts). The `orderPinnedFirst()` function separates pinned nodes (where `node.pinned` is `true`) from un-pinned ones and concatenates them so pinned items appear at the top. Pin state is stored in the persisted layout (`SidebarLayout.groups` and the `pinned` flag on nodes).

```typescript
// Pin a connection (e.g., from a UI button)
import { appendConnectionToLayout } from '@/lib/sidebar/sidebarLayout';

function pinConnection(id: string) {
  const newLayout = appendConnectionToLayout(currentLayout.value, id);
  // persist newLayout → DBX stores it in the user config file
  currentLayout.value = newLayout;
}

```

While building the tree, `buildTreeNodesFromLayout()` marks any node whose `id` appears in the user’s `pinnedIds` set as `pinned: true`. After the tree is built, `orderPinnedFirst()` re-orders the top-level nodes so that all pinned connections and groups appear before regular ones.

## Object Grouping Modes: Simple vs. Grouped

DBX can display objects in two visual modes controlled by the user setting `editorSettings.sidebarObjectDisplay`.

In **simple** mode, the sidebar shows a flat list of tables and views under each schema. In **grouped** mode, objects are first grouped by kind—such as Tables, Views, and Procedures—before being listed. The grouping logic lives in [`apps/desktop/src/lib/sidebar/sidebarNodeOrdering.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sidebar/sidebarNodeOrdering.ts), which re-orders children according to the chosen display mode.

```typescript
// Switch object grouping mode (simple ↔ grouped)
import { useSettingsStore } from '@/stores/settingsStore';
import { orderSidebarChildrenForGroup } from '@/lib/sidebar/sidebarNodeOrdering';

function toggleGroupMode() {
  const settings = useSettingsStore();
  settings.editorSettings.sidebarObjectDisplay =
    settings.editorSettings.sidebarObjectDisplay === 'simple' ? 'grouped' : 'simple';
  // The node ordering logic listens to this setting and recomputes the tree.
}

```

The `buildTreeNodesFromLayout()` function creates the initial tree, and then `orderPinnedFirst()` combined with the node-ordering step in [`sidebarNodeOrdering.ts`](https://github.com/t8y2/dbx/blob/main/sidebarNodeOrdering.ts) produces the final UI hierarchy.

## Integrating Search, Pins, and Grouping

The final visible sidebar results from a pipeline that combines layout creation, schema loading, search filtering, pinning, and grouping.

**Layout creation** occurs when a connection is added, building a `SidebarLayout` from persisted data and the set of connections. **Schema loading** happens in [`apps/desktop/src/stores/connectionStore.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/stores/connectionStore.ts), which retrieves schema information via the database driver (`api.listSchemas()`, `api.listTables()`, etc.) and caches it using a `schemaTreeCache`. Each node’s type is set to `"schema"` or `"object-browser"` and children are populated accordingly.

The integration flow follows this sequence:

1. **Build raw tree** – `buildTreeNodesFromLayout()` constructs the tree from layout and connections, marking pinned nodes.
2. **Apply search** – `filterSidebarTree()` prunes the tree based on the search query and collapsed node IDs.
3. **Order pins** – `orderPinnedFirst()` ensures pinned nodes appear first.
4. **Group objects** – `sidebarNodeOrdering` functions rearrange children based on the `sidebarObjectDisplay` setting.

```typescript
// Complete pipeline assembling the final sidebar tree
const rawTree = buildTreeNodesFromLayout(layout, connections, pinnedIds);
const displayedTree = filterSidebarTree(
    rawTree,
    sidebarSearchQuery.value,
    collapsedNodeIds,
    searchableNodeTypes   // varies per display mode
);

```

The UI renders `displayedTree`, handling expand/collapse, drag-and-drop, and group operations through helpers in [`sidebarLayout.ts`](https://github.com/t8y2/dbx/blob/main/sidebarLayout.ts).

## Summary

- **Tree Structure** – DBX uses `TreeNode` objects with types defined in [`apps/desktop/src/types/database.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/types/database.ts) to represent the schema hierarchy.
- **Search** – `filterSidebarTree()` in [`sidebarSearchTree.ts`](https://github.com/t8y2/dbx/blob/main/sidebarSearchTree.ts) implements fuzzy matching while preserving parent contexts for matches.
- **Pinning** – The `orderPinnedFirst()` function ensures pinned nodes appear first, with state persisted in `SidebarLayout`.
- **Grouping** – The `sidebarObjectDisplay` setting controls whether objects are flat or grouped by type, handled by [`sidebarNodeOrdering.ts`](https://github.com/t8y2/dbx/blob/main/sidebarNodeOrdering.ts).
- **Integration** – The sidebar pipeline combines `buildTreeNodesFromLayout()`, filtering, pin ordering, and grouping to produce the final tree.

## Frequently Asked Questions

### How does DBX filter the schema tree during search?

DBX uses the `filterSidebarTree()` function in [`apps/desktop/src/lib/sidebar/sidebarSearchTree.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sidebar/sidebarSearchTree.ts), which scores nodes using `createSidebarLabelMatcher` for fuzzy matching. It preserves sub-trees for node types like connections, databases, and schemas so that matching tables still show their parent hierarchy, resulting in a pruned but contextually complete tree.

### Where does DBX store the pinned state of sidebar items?

The pinned state is stored in the `SidebarLayout` object, specifically in the `groups` array and the `pinned` boolean flag on each `TreeNode`. The `orderPinnedFirst()` function in [`apps/desktop/src/lib/sidebar/sidebarLayout.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sidebar/sidebarLayout.ts) uses this data to reorder nodes during tree construction, and the layout is persisted to the user's config file.

### What determines whether objects are grouped by type in the DBX sidebar?

The `editorSettings.sidebarObjectDisplay` setting controls the display mode. When set to `"grouped"`, the [`sidebarNodeOrdering.ts`](https://github.com/t8y2/dbx/blob/main/sidebarNodeOrdering.ts) logic rearranges children under each schema into sub-groups (Tables, Views, Procedures). When set to `"simple"`, objects appear as a flat list under their parent schema.

### How does DBX persist the sidebar layout between sessions?

DBX persists the layout through the `SidebarLayout` interface, which stores connection order, group configurations, expansion states, and pinned node IDs. The `buildTreeNodesFromLayout()` and `reconcileLayout()` functions in [`apps/desktop/src/lib/sidebar/sidebarLayout.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sidebar/sidebarLayout.ts) handle serialization and deserialization, ensuring the sidebar state survives application restarts.