Implementation:TobikoData Sqlmesh Story ModelLineage
| Knowledge Sources | |
|---|---|
| Domains | Data_Lineage, Web_UI, Graph_Visualization, Model_Management |
| Last Updated | 2026-02-07 20:00 GMT |
Overview
React component for rendering complete model lineage graphs with column-level lineage support.
Description
ModelLineage is a comprehensive React component that orchestrates the visualization of SQLMesh model dependencies and column-level lineage. It uses ReactFlow for graph rendering and implements a Web Worker-based layout algorithm (Dagre) to compute optimal node positions asynchronously, preventing UI blocking during complex graph calculations.
The component supports advanced features including:
- Toggle between full lineage and selected-node-only view
- Column-level lineage visualization with port-to-port connections
- Dynamic node height calculation based on column count and zoom level
- Lazy-loading of column lineage data
- State management via React Context (ModelLineageContext)
The implementation uses branded types extensively to ensure type safety across model names, column names, and IDs, preventing accidental mixing of different identifier types.
Usage
Use this component to display interactive model dependency graphs in the SQLMesh web UI. It's the primary interface for understanding model relationships, dependencies, and column-level data flow.
Code Reference
Source Location
- Repository: TobikoData_Sqlmesh
- File: web/common/src/components/Lineage/stories/ModelLineage.tsx
Signature
export const ModelLineage = ({
selectedModelName,
adjacencyList,
lineageDetails,
className,
}: {
adjacencyList: BrandedLineageAdjacencyList
lineageDetails: BrandedLineageDetails
selectedModelName?: ModelName
className?: string
})
Import
import { ModelLineage } from '@sqlmesh-common/components/Lineage/stories/ModelLineage'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| adjacencyList | BrandedLineageAdjacencyList | Yes | Model dependency graph (source → targets) |
| lineageDetails | BrandedLineageDetails | Yes | Detailed model metadata (kind, type, columns, etc.) |
| selectedModelName | ModelName | No | Name of initially selected model |
| className | string | No | Additional CSS classes for styling |
Outputs
| Name | Type | Description |
|---|---|---|
| Interactive Graph | JSX.Element | Rendered ReactFlow graph with nodes and edges |
| Context State | ModelLineageContext | Shared state for descendant components |
Implementation Details
Key Features
Node Transformation
- Dynamic Height Calculation: Nodes resize based on column count, details, and zoom level
- Metadata Mapping: Transforms API response to node data (name, type, kind, cron, owner, dialect, version, tags, columns)
- Type Safety: Uses branded types to prevent ID confusion (ModelNodeId, ModelColumnID, ModelEdgeId)
Edge Transformation
- Gradient Colors: Edges colored based on source/target node types using CSS variables
- Port Edges: Column-level connections have different colors and stroke width (2px vs default)
- Adaptive Edge Type: Switches between node-level and column-level edges based on state
Layout Calculation
- Web Worker: Uses `dagreLayout.worker.ts` to compute graph layout asynchronously
- Non-Blocking: UI remains responsive during layout computation
- Cleanup: Worker terminated on component unmount to prevent memory leaks
- Error Handling: Falls back to empty graph on layout failure
Column-Level Lineage
- Lazy Loading: Column lineage fetched on demand (tracked via `fetchingColumns` set)
- Caching: Column lineage stored in `columnLevelLineage` Map
- Toggle: Show/hide columns via `showColumns` state
- Filtered Display: Large column lists (> MAX_COLUMNS_TO_DISPLAY) show with filter input
State Management
- Context Provider: ModelLineageContext provides state to all descendant components
- Shared State: zoom, nodes, edges, selected nodes/edges/columns, column lineage
- Actions: setZoom, setShowColumns, setSelectedNodeId, setColumnLevelLineage, etc.
Control Buttons
- Show/Hide Columns: Toggle column-level detail (Rows2/Rows3 icons)
- Reset: Clear all selections and return to full graph view (Focus icon)
- Inherited Controls: From LineageLayoutBase (Only Selected Nodes, Zoom to Node)
Performance Optimizations
- Only Render Visible: ReactFlow's `onlyRenderVisibleElements` enabled
- Memoized Transformations: `transformedNodesMap` and `transformedEdges` use `React.useMemo`
- Debounced Zoom: Zoom updates debounced to prevent excessive re-renders (via LineageLayoutBase)
- Adaptive Zoom Limits: Min zoom reduces for graphs with > NODES_TRESHOLD nodes
Usage Examples
// Basic model lineage
<ModelLineage
adjacencyList={{
'model_a': ['model_b', 'model_c'],
'model_b': ['model_d'],
}}
lineageDetails={{
'model_a': {
name: 'model_a',
display_name: 'schema.model_a',
model_type: 'sql',
kind: 'incremental_by_time_range',
columns: { id: { name: 'id', data_type: 'INT' } },
// ... other metadata
},
// ... other models
}}
selectedModelName="model_b"
/>
// Column-level lineage with initial state
const [columnLevelLineage, setColumnLevelLineage] = useState(new Map())
// Fetch column lineage on demand
useEffect(() => {
if (showColumns) {
fetchColumnLineage('model_a').then(data => {
setColumnLevelLineage(prev =>
new Map(prev).set('model_a::column_id', data)
)
})
}
}, [showColumns])
<ModelLineage
adjacencyList={adjacencyList}
lineageDetails={lineageDetails}
/>