How DBX Implements Its Schema Browser with Sidebar Search, Pinning, and Object Grouping
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. 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. 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. The filterSidebarTree() function uses a fuzzy label matcher (createSidebarLabelMatcher from 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.
// 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. 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).
// 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, which re-orders children according to the chosen display mode.
// 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 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, 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:
- Build raw tree –
buildTreeNodesFromLayout()constructs the tree from layout and connections, marking pinned nodes. - Apply search –
filterSidebarTree()prunes the tree based on the search query and collapsed node IDs. - Order pins –
orderPinnedFirst()ensures pinned nodes appear first. - Group objects –
sidebarNodeOrderingfunctions rearrange children based on thesidebarObjectDisplaysetting.
// 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.
Summary
- Tree Structure – DBX uses
TreeNodeobjects with types defined inapps/desktop/src/types/database.tsto represent the schema hierarchy. - Search –
filterSidebarTree()insidebarSearchTree.tsimplements fuzzy matching while preserving parent contexts for matches. - Pinning – The
orderPinnedFirst()function ensures pinned nodes appear first, with state persisted inSidebarLayout. - Grouping – The
sidebarObjectDisplaysetting controls whether objects are flat or grouped by type, handled bysidebarNodeOrdering.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, 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 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 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 handle serialization and deserialization, ensuring the sidebar state survives application restarts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →