Skip to Content
LearnTroubleshootingMigrating to 2.0

Migrating to Vue Flow 2.0

Vue Flow 2.0 rebuilds the core on top of @xyflow/system — the framework-agnostic engine that also powers React Flow and Svelte Flow. The payoff is a smaller, faster, and far more consistent API: the same node/edge model, the same accessor names, and the same store shape across the three libraries.

That alignment means breaking changes. This guide walks through them, grouped by theme, with before/after for each. If you just want the lookup tables, jump to the cheat sheet.

Most apps are touched by §1 (one package), §2 (v-model), and §3 (immutability) — start there.

1. One package: @xyflow/vue

Vue Flow 2.0 is published under a new name — @xyflow/vue — and that single package ships every built-in: Background, Controls, MiniMap, NodeToolbar, NodeResizer/NodeResizeControl. The @vue-flow/core package and the separate @vue-flow/node-resizer, @vue-flow/node-toolbar, @vue-flow/background, @vue-flow/controls, and @vue-flow/minimap add-ons are all replaced by it.

// before import { VueFlow } from '@vue-flow/core'; import { NodeResizer } from '@vue-flow/node-resizer'; import { NodeToolbar } from '@vue-flow/node-toolbar'; import '@vue-flow/core/dist/style.css'; import '@vue-flow/node-resizer/dist/style.css'; // after — everything from one package import { NodeResizer, NodeToolbar, VueFlow } from '@xyflow/vue'; import '@xyflow/vue/style.css'; // ships the resize-control styles too

Uninstall the @vue-flow/* packages and install @xyflow/vue, then bump the peers: Vue Flow 2.0 requires Vue >=3.5 (it uses useId()) and @vueuse/core v14.

2. Binding nodes & edges

The combined v-model="elements" (and the whole mixed-elements API) is removed. Nodes and edges are separate.

<!-- before --> <VueFlow v-model="elements" /> <!-- after — separate, two-way bindings --> <VueFlow v-model:nodes="nodes" v-model:edges="edges" /> <!-- or one-way --> <VueFlow :nodes="nodes" :edges="edges" />

The element-bucket actions are gone too — use the node/edge equivalents:

RemovedUse
setElements(...)setNodes(...) + setEdges(...)
addSelectedElements(...)addSelectedNodes(...) / addSelectedEdges(...)
getElements / getSelectedElementsgetNodes / getEdges / getSelectedNodes / getSelectedEdges

The binding decides how changes are handled

The applyDefault prop is removed — the binding you choose now determines this:

  • v-model:nodes / v-model:edges (or no binding at all, when driving the flow through useVueFlow() / setupVueFlow()) is managed: Vue Flow applies changes (drag, select, remove) to its store and mirrors them back to your ref.
  • A bare one-way :nodes / :edges is controlled: changes are delivered via @nodes-change / @edges-change and nothing is applied until you handle them. What those events hand you changed in 2.0, see Changes are a changeset, not an array.
<!-- managed --> <VueFlow v-model:nodes="nodes" v-model:edges="edges" /> <!-- controlled --> <VueFlow :nodes="nodes" :edges="edges" @nodes-change="(changes) => (nodes = changes.applyTo(nodes))" @edges-change="(changes) => (edges = changes.applyTo(edges))" />

3. Changes are a changeset, not an array

@nodes-change / @edges-change — and the onNodesChange / onEdgesChange hooks — used to hand you a NodeChange[] / EdgeChange[], which you applied with the standalone applyNodeChanges / applyEdgeChanges helpers. They now hand you a changeset: a NodeChangeset or EdgeChangeset that carries the changes queued for that update and knows how to apply them.

This only concerns you if you run a controlled flow (a one-way :nodes / :edges binding) or listen to the change events yourself. With v-model Vue Flow applies the changeset for you.

Applying changes

Call applyTo with your current array; it returns the next one.

// before import { applyEdgeChanges, applyNodeChanges } from '@xyflow/vue'; function onNodesChange(changes: NodeChange[]) { nodes.value = applyNodeChanges(changes, nodes.value); } function onEdgesChange(changes: EdgeChange[]) { edges.value = applyEdgeChanges(changes, edges.value); }
// now import type { Edge, EdgeChangeset, Node, NodeChangeset } from '@xyflow/vue'; function onNodesChange(changes: NodeChangeset<Node>) { nodes.value = changes.applyTo(nodes.value); } function onEdgesChange(changes: EdgeChangeset<Edge>) { edges.value = changes.applyTo(edges.value); }

Reading changes

A changeset is iterable, and it can hand you changes by type or by element — so you no longer scan an array to find out what happened.

// before if (changes.some((change) => change.type === 'remove')) { saveUndoSnapshot(); } // now if (changes.getByType('remove').length > 0) { saveUndoSnapshot(); }
for (const change of changes) { console.log(change.type, change.id); } changes.toArray(); // every queued change, as a flat array changes.getForNode('node-1'); // everything queued for one node (getForEdge on an EdgeChangeset) changes.size; // how many elements the changeset touches

Editing a changeset before applying it

Because it’s a real object rather than an array you rebuild, you can drop or add changes before applying — useful for vetoing part of an update.

function onNodesChange(changes: NodeChangeset<Node>) { // ignore anything that would move or delete the locked node changes.removeForNode('locked-node'); nodes.value = changes.applyTo(nodes.value); }

add(change) queues a change and remove(change) drops one by reference. You can also build a changeset from scratch — handy in tests, or in a helper that transforms changes before handing them back:

import { NodeChangeset } from '@xyflow/vue'; const changes = new NodeChangeset([{ id: 'node-1', type: 'select', selected: true }]); nodes.value = changes.applyTo(nodes.value);

What happened to applyNodeChanges / applyEdgeChanges

Both are still exported, but they are deprecated and still array-based, so they cannot take the event payload directly. Use the changeset’s applyTo, or the instance methods of the same name from useVueFlow() — those take a changeset and write straight to the store:

const { applyNodeChanges } = useVueFlow(); function onNodesChange(changes: NodeChangeset<Node>) { applyNodeChanges(changes); // no reassignment needed }

If you have to keep using the deprecated util, hand it changes.toArray().

The individual change shapes were renamed in the same release (NodePositionChange → PositionChange, and so on) — see Types & change shapes.

4. Nodes and edges are immutable

This is the most important behavioral change. To skip deep-reactifying every node and edge (a big perf win on large graphs), Vue Flow no longer tracks in-place mutations of the objects you pass in.

// ❌ no longer triggers a re-render const node = getNode('1'); node.position = { x: 10, y: 10 }; node.data.label = 'changed'; node.selected = true; edge.animated = !edge.animated;

Update through the store helpers, or reassign your v-model array immutably:

const { updateNode, updateNodeData, updateEdge, updateEdgeData, setNodes, setEdges } = useVueFlow(); updateNode('1', { position: { x: 10, y: 10 } }); updateNodeData('1', { label: 'changed' }); updateEdge('e1-2', { animated: true }); // or immutable reassignment of the bound array nodes.value = nodes.value.map((n) => (n.id === '1' ? { ...n, selected: true } : n));

Two related changes:

  • Node defaults are no longer stamped. A node passed without data keeps data: undefined (was {}); selected/dragging stay undefined until set. Guard optional reads: node.data?.label.
  • getNodes/getEdges/getSelectedNodes/getSelectedEdges return readonly arrays. .filter/.map work fine; reassign/push is a type error — change membership via setNodes/addNodes/etc.

5. The node shape: Node vs InternalNode

Your nodes array (v-model:nodes, store.nodes, getNodes(), getNode(id)) now returns the raw Nodes you passed in — no store-computed fields. The enriched node (absolute position, z-index, measured size, handle bounds) is the InternalNode, kept in nodeLookup and reached via new accessors:

const { getInternalNode } = useVueFlow(); const internal = getInternalNode('1'); // InternalNode internal.internals.positionAbsolute; internal.measured; // { width, height } // or as a composable (re-resolves reactively) import { useInternalNode } from '@xyflow/vue'; const node = useInternalNode('1');

Field moves on the node:

Before (top-level)After
node.parentNodenode.parentId
node.computedPositionnode.internals.positionAbsolute (+ node.internals.z)
node.dimensionsnode.measured
node.handleBoundsnode.internals.handleBounds
node.isParentparentLookup.get(node.id)?.size > 0
node.label (top-level)node.data.label

useNode now returns the user-facing Node (it used to return the enriched InternalNode) — reach for useInternalNode when you need internals/measured. Its id argument also accepts a ref or getter.

Custom node components are unaffected — they still receive position, dimensions, etc. through their props. But node event payloads now carry the user Node, not the InternalNode (xyflow parity) — onNodeClick, onNodeDrag*, the minimap node events, nodesInitialized, etc. emit your raw node. If a handler read store-computed fields off the event node, resolve the enriched node by id: getInternalNode(node.id).

6. The edge shape: no more GraphEdge

Edges are stored verbatim as your plain Edge objects — there is no enriched edge representation.

  • GraphEdge and isGraphEdge are removed — use Edge.
  • edge.sourceNode / edge.targetNode / edge.sourceX no longer exist. In a custom edge, resolve nodes with useInternalNode(() => props.source) and read positions straight off EdgeProps (sourceX, sourceY, …).
  • EdgeProps drops sourceNode/targetNode, exposes handles as sourceHandleId/targetHandleId, gains selectable/deletable, and makes type/data optional.
  • useEdge().edge is now a ComputedRef.
  • The per-edge template option (edge.template) is removed — use edge slots (#edge-<type>) or map an edge type to a component via the edgeTypes prop.
  • Auto-generated edge IDs use the xy-edge__ prefix (was vueflow__edge-), matching react/svelte — this only affects edges created without an explicit id. Update any CSS/selectors or persisted references that matched vueflow__edge-.
  • setEdges/addEdges keep edges whose source/target node isn’t in the store yet (the edge simply isn’t drawn until both nodes exist, emitting the EDGE_SOURCE_MISSING/EDGE_TARGET_MISSING dev warning). The order of setNodes vs setEdges no longer matters.

7. The store split: useVueFlow + useVueFlowStore

useVueFlow() is now the curated instance — actions, computed getters, and event hooks. The raw reactive state moved to useVueFlowStore(), with storeToRefs() as the Pinia-style destructure bridge.

// before — everything off useVueFlow() const { nodes, transform, nodeLookup, setViewport, onConnect } = useVueFlow(); // after const { setViewport, onConnect, getNodes } = useVueFlow(); // actions + getters + hooks const { nodes, transform } = storeToRefs(useVueFlowStore()); // value-type state → refs const { nodeLookup } = useVueFlowStore(); // reactive-Map lookups (no .value)

Inside a component (incl. custom nodes/edges), prefer reading the store directly — const store = useVueFlowStore() then store.transform, store.nodesDraggable, … . Reads inside a computed/render track reactively without .value, and you skip re-projecting the whole state into refs on every instance.

BeforeAfter
const { nodes } = useVueFlow()const { nodes } = storeToRefs(useVueFlowStore())
const { transform, dimensions, nodesDraggable } = useVueFlow()const { transform, dimensions, nodesDraggable } = storeToRefs(useVueFlowStore())
const { nodeLookup } = useVueFlow()const { nodeLookup } = useVueFlowStore()
const { setViewport, getNodes, onConnect } = useVueFlow()unchanged

There is intentionally no useStoreApi — Vue’s reactivity makes it redundant (useVueFlowStore() serves both reactive reads and current-value reads; subscribe with watch(() => store.x, …)).

The ongoing connection is also consolidated: the separate connectionStartHandle, connectionEndHandle, connectionPosition, and connectionStatus store fields are replaced by a single connection object (ConnectionState). Read connection.fromHandle, connection.toHandle, connection.pointer, and connection.isValid — matching useConnection().

8. No global registry — the provider model

useVueFlow() no longer takes any argument; it’s a pure consumer that returns the store from the nearest <VueFlow> / <VueFlowProvider> ancestor (and throws if there isn’t one). The global flow registry and the $vueFlowStorage singleton are gone.

// before const { ... } = useVueFlow({ nodes, edges, id: 'my-flow' }); const { ... } = useVueFlow('my-flow'); // reach a flow from outside // after — pass options as props, consume with no args from any descendant const { ... } = useVueFlow();

Multiple flows on a page each get their own <VueFlowProvider> (or <VueFlow>) tree — they no longer share a registry, so they can’t collide and don’t need distinct ids.

<VueFlowProvider> accepts the same options as setupVueFlow() to seed its store — pass nodes, edges, or any other VueFlowProps and they become the store’s initial values (read once at creation):

<VueFlowProvider :nodes="initialNodes" :edges="initialEdges"> <Toolbar /> <VueFlow /> </VueFlowProvider>

When you own the component that renders <VueFlow>, prefer setupVueFlow(), the composable form that provides (and seeds) the store from the same <script setup> without a wrapper component.

9. API renames (xyflow parity)

findNode(id) → getNode(id) findEdge(id) → getEdge(id) project(point) → screenToFlowPosition(point) screenToFlowCoordinate → screenToFlowPosition flowToScreenCoordinate → flowToScreenPosition

Edge “update” → “reconnect” (xyflow v12 vocabulary):

BeforeAfter
updateEdge(oldEdge, connection)reconnectEdge(oldEdge, connection)
@edge-update-start / @edge-update / @edge-update-end@reconnect-start / @reconnect / @reconnect-end
edgeUpdaterRadiusreconnectRadius
edges-updatable / edge.updatableedges-reconnectable / edge.reconnectable
EdgeUpdatable / EdgeUpdateEventEdgeReconnectable / EdgeReconnectEvent

updateEdge is reused for a new purpose: updateEdge(id, edgeUpdate, { replace? }) — a partial edge update (the edge analogue of updateNode). Edge reconnection is now reconnectEdge.

Instance actions: $reset → reset, and $destroy is removed (it was a no-op — the store is owned by its provider and torn down when that component unmounts).

isValidConnection now receives only the attempted connection, matching React/Svelte Flow. The second argument ({ nodes, edges, sourceNode, targetNode }) is removed — read those from useVueFlow() inside your handler if you need them.

<Handle> props connectableStart / connectableEnd → isConnectableStart / isConnectableEnd.

useConnection returns a ComputedRef<ConnectionState> — { inProgress, isValid, from, fromHandle, fromPosition, fromNode, to, toHandle, toPosition, toNode, pointer } — instead of { startHandle, endHandle, status, position }.

VueFlowStore → VueFlowInstance (the type returned by useVueFlow() / exposed by a <VueFlow> template ref). The old VueFlowStore name is removed.

10. connectionMode defaults to strict

In strict mode a source handle only connects to a target handle (and vice-versa) — same-type connections are rejected. To restore the old behavior where every handle acts as a source:

<VueFlow connection-mode="loose" />

11. Init / fit props & defaults

BeforeAfter
:fit-view-on-init="true":fit-view="true"
(initial fit was not configurable):fit-view-options="{ padding: 0.2, maxZoom: 1 }"
  • fitView() now queues — it waits for the nodes to be committed and measured before fitting, so it frames the current graph even right after addNodes() or a reposition. You no longer need a nextTick() before fitView(). It returns a promise you can optionally await.
  • fitView / fitBounds default padding is now 5%.
  • edgesReconnectable and elevateEdgesOnSelect now default to true. Edges are reconnectable by default (only in effect once you handle @reconnect) and selected edges are raised above their siblings — set :edges-reconnectable="false" / :elevate-edges-on-select="false" to opt out.
  • nodeOrigin is now actually honored (it was previously ignored), and a new nodeClickDistance prop sets how far the pointer may move and still count as a node click.

Viewport option types now reuse @xyflow/system (renamed; same shape unless noted):

Before (vue-flow)After (@xyflow/system)
FitViewParamsFitViewOptions
TransitionOptionsViewportHelperFunctionOptions
ViewportPositionFuncProject
  • fitView({ nodes }) takes node objects, not ids: fitView({ nodes: ['a', 'b'] }) → fitView({ nodes: [{ id: 'a' }, { id: 'b' }] }).
  • fitView’s offset option is removed — use padding (a number, a '10px'/'5%' string, or { top, right, bottom, left }).
  • New ease + interpolate options on every viewport function, alongside duration.

12. Deleting elements

  • removeNodes removes connected edges by default (removeNodes(nodes, removeConnectedEdges = true, removeChildren = false)). Pass false to keep the edges.
  • New onBeforeDelete prop — a guard consulted before delete-key / deleteElements removals; return false to cancel, true to proceed, or { nodes, edges } to delete a subset.
  • New deleteElements({ nodes, edges }) action — deletes the given elements plus their connected edges and children (gated by onBeforeDelete), resolving to the removed set.
  • New nodesDelete / edgesDelete / delete events (onNodesDelete / onEdgesDelete / onDelete) fire from deleteElements after onBeforeDelete resolves. The OnDelete handler type is exported alongside OnBeforeDelete.

13. Removed deprecated APIs

RemovedUse
autoConnect prop / Connector type@connect (or onConnect) + addEdge/addEdges
useHandleConnectionsuseNodeConnections (type→handleType (optional), id→handleId)
HandleConnection typeNodeConnection
connectionLineType / connectionLineStyle propsconnectionLineOptions.type / .style
paneReady eventinit (@init / onInit)
FlowExportObject.position / .zoomFlowExportObject.viewport ({ x, y, zoom })
updateNodeInternals() (no-arg form)updateNodeInternals(id) / updateNodeInternals(ids)
useZoomPanHelperuseVueFlow() zoom/pan actions (zoomIn, zoomOut, fitView, setViewport)
useVueFlow().fromObject() / FlowImportObjectrestore manually after onInit (set nodes/edges + setViewport); toObject() is unchanged

Handle new connections with @connect + addEdge (the autoConnect replacement):

<VueFlow @connect="(connection) => (edges = addEdge(connection, edges))" />

14. Types & change shapes

  • NodeProps/EdgeProps take the element type, not the data type: NodeProps<MyData> → NodeProps<Node<MyData, 'myType'>> (same for EdgeProps<Edge<MyData, 'myType'>>).
  • GraphNode is renamed to InternalNode (and the isGraphNode guard to isInternalNode).
  • HandleElement → Handle and EdgePositions → EdgePosition; the deprecated Project type is no longer re-exported, and OnConnectStartParams fields are now nullable.
  • useVueFlow<NodeType, EdgeType>() is fully typed on both generics (xyflow order).
  • Padding uses @xyflow/system’s Padding type for both fitView/fitBounds and a node extent’s padding. A plain number still works; you can also pass a '10px'/'5%' string or a per-side object. The old positional-tuple extent padding is removed: padding: [10, 20] → padding: { y: 10, x: 20 }.
  • Custom connection lines use from*/to* props. ConnectionLineProps moved from source*/target* to xyflow’s from*/to* (sourceX → fromX, targetNode → toNode, …). markerStart/markerEnd are now optional.
  • An edge’s data defaults to Record<string, unknown> (was any, via the now-removed ElementData).
  • Changes are delivered as a changeset, not a NodeChange[] / EdgeChange[] — see its own section.
  • Change types mirror @xyflow/system, and the per-element names are gone. The node/edge prefixes were dropped now that the shapes are shared: NodeDimensionChange → DimensionChange, NodePositionChange → PositionChange, NodeSelectionChange/EdgeSelectionChange → SelectionChange, NodeAddChange/EdgeAddChange → AddChange, NodeRemoveChange/EdgeRemoveChange → RemoveChange. (NodeChange and EdgeChange — the unions you actually receive — keep their names.) Their fields moved too: updateStyle → setAttributes, from → positionAbsolute, an add change’s item is the user Node/Edge (with an optional index), and a remove change is { id, type: 'remove' } only.
  • PanelPositionType → PanelPosition (@xyflow/system’s type). It now also accepts 'center-left' and 'center-right'.
  • ConnectionLineType.SimpleBezier’s value changed from 'simple-bezier' to 'simplebezier'; use the enum rather than the raw string and nothing changes.
  • The catch-all object was dropped from the edge label type (EdgeProps/EdgeTextProps/BaseEdgeProps) so it matches the actual string | VNode | Component.

15. Styles & CSS variables

The stylesheets and theme variables now mirror @xyflow/react/@xyflow/svelte.

theme-default.css was removed. style.css is now the full default theme (necessary structure and the built-in look) — import just that. A new base.css ships the structure with only minimal theming.

// before import '@vue-flow/core/dist/style.css'; // structure only import '@vue-flow/core/dist/theme-default.css'; // the default theme // after — style.css IS the full theme import '@xyflow/vue/style.css'; // …or theme it yourself on top of the minimal base: // import '@xyflow/vue/base.css';

--vf-* → --xy-*. The theme custom properties are renamed to the shared --xy-* set (identical to react/svelte). Each rule reads var(--xy-x, var(--xy-x-default)), so override the un-suffixed variable and Vue Flow falls back to the shipped --xy-x-default. The common ones:

beforeafter
--vf-node-bg--xy-node-background-color
--vf-node-text--xy-node-color
--vf-handle--xy-handle-background-color
--vf-handle-border--xy-handle-border-color
--vf-connection-path--xy-edge-stroke / --xy-connectionline-stroke
--vf-edge-text--xy-edge-label-color
--vf-edge-text-bg--xy-edge-label-background-color
--vf-controls-bg--xy-controls-button-background-color
--vf-minimap-bg--xy-minimap-background-color

Three element classes were renamed to match xyflow. The internal DOM now nests exactly like @xyflow/react/@xyflow/svelte — renderer (outer pan/zoom container) › pane (drag/selection surface) › viewport (the transformed layer):

beforeafter
.vue-flow__transformationpane.vue-flow__viewport
.vue-flow__viewport.vue-flow__renderer
.vue-flow__edge-labels.vue-flow__edgelabel-renderer

Note viewport now refers to the transformed inner layer (it was the outer container before). Everything keeps the vue-flow__ prefix.

Uniform node accents. The built-in input/output node types no longer have blue/pink accent borders — every default node type uses the same neutral border. Re-add per-type colors with your own CSS if you want them.

16. selectionKeyCode={true} → selectionOnDrag

Drawing a selection box on a plain drag (no key held) used to be expressed by setting selectionKeyCode to true. It’s now an explicit boolean prop, selectionOnDrag, matching @xyflow/react:

<!-- before --> <VueFlow :selection-key-code="true" :pan-on-drag="false" /> <!-- after --> <VueFlow :selection-on-drag="true" :pan-on-drag="false" />

selectionKeyCode goes back to being just the key you hold to select (default 'Shift'). Pair selectionOnDrag with :pan-on-drag="false" or a non-left button (e.g. :pan-on-drag="[1, 2]") so a left-drag selects instead of panning.

Cheat sheet

// packages '@vue-flow/core' | '@vue-flow/node-resizer' | '@vue-flow/node-toolbar' | … → '@xyflow/vue' import 'theme-default.css' → removed; '@xyflow/vue/style.css' is the full theme (or base.css for minimal) // binding & changes <VueFlow v-model="elements"> → <VueFlow v-model:nodes="nodes" v-model:edges="edges"> applyDefault prop → removed; v-model = managed, one-way :nodes/:edges = controlled @nodes-change payload → NodeChangeset/EdgeChangeset (was NodeChange[]/EdgeChange[]) applyNodeChanges(changes, ns) → changes.applyTo(ns) changes.some(c => c.type===x) → changes.getByType(x).length > 0 NodePositionChange etc. → PositionChange/DimensionChange/SelectionChange/AddChange/RemoveChange // store useVueFlow().nodes / .transform / .nodeLookup → storeToRefs(useVueFlowStore()) / useVueFlowStore() useVueFlow(id | options) → useVueFlow() inside <VueFlow>/<VueFlowProvider> connectionStartHandle / … → connection (ConnectionState) // accessors & helpers findNode/findEdge → getNode/getEdge project → screenToFlowPosition updateEdge(old, conn) → reconnectEdge(old, conn) @edge-update* → @reconnect* $reset / $destroy → reset / (removed) updateNodeInternals() → updateNodeInternals(id) // no-arg form removed autoConnect prop → @connect + addEdge // node fields node.parentNode → node.parentId node.computedPosition → getInternalNode(id).internals.positionAbsolute node.dimensions → getInternalNode(id).measured node.label → node.data.label useNode(id) → user Node (was InternalNode); useInternalNode(id) for internals // types VueFlowStore → VueFlowInstance GraphEdge / GraphNode → Edge / InternalNode HandleElement → Handle EdgePositions → EdgePosition NodeProps<Data> → NodeProps<Node<Data, 'type'>> PanelPositionType → PanelPosition // + 'center-left' / 'center-right' FitViewParams → FitViewOptions // behavior & defaults node.x = … → updateNode(id, { x: … }) / immutable reassignment removeNodes(id) → also removes connected edges (pass `false` to keep them) connectionMode → defaults to 'strict' edgesReconnectable / elevateEdgesOnSelect → default to true fitView() → queues (no nextTick needed); default padding now 5% :selection-key-code="true" → :selection-on-drag="true"

Hitting something this guide doesn’t cover? Open an issue  — it likely belongs here.

Last updated on