diff --git a/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx b/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx
index 1c761a6a293617198708186c3b2b5b7b5b294722..fb0fcb6a919311c900b1ba40e13b5cac290330d6 100644
--- a/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx
+++ b/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx
@@ -172,7 +172,7 @@ export const SettingsForm = (props: { onClose(): void; open: 'add' | 'update'; s
             <Button
               variantType="primary"
               className="flex-grow"
-              label={connection.updating ? formTitle.slice(0, -1) + 'ing...' : formTitle}
+              label={connection.updating ? (formTitle === 'Add' ? formTitle + 'ing...' : formTitle.slice(0, -1) + 'ing...') : formTitle}
               onClick={(event) => {
                 event.preventDefault();
                 handleSubmit();
diff --git a/libs/shared/lib/components/pills/Pill.tsx b/libs/shared/lib/components/pills/Pill.tsx
index b107d1d88062ddbacf58b7ca2ac36cdc839a38c2..a479ef713d6e2e8282d2671b432397e356139429 100644
--- a/libs/shared/lib/components/pills/Pill.tsx
+++ b/libs/shared/lib/components/pills/Pill.tsx
@@ -101,7 +101,7 @@ export const Pill = React.memo((props: PillI) => {
             ></div>
           )}
           <div
-            className={'font-semibold bg-neutral-100 ' + (corner !== 'square' ? 'rounded-b-[3px]' : '')}
+            className={'font-semibold ' + (corner !== 'square' ? 'rounded-b-[3px]' : '')}
             onMouseEnter={onMouseEnter}
             onMouseLeave={onMouseLeave}
           >
diff --git a/libs/shared/lib/querybuilder/model/graphology/metaAttributes.ts b/libs/shared/lib/querybuilder/model/graphology/metaAttributes.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4c34d0884ba11b1602fcb13596f35e0b1cdcee00
--- /dev/null
+++ b/libs/shared/lib/querybuilder/model/graphology/metaAttributes.ts
@@ -0,0 +1,28 @@
+import { SchemaAttribute } from '../../..';
+import { Handles, QueryElementTypes } from '../reactflow';
+import { QueryGraphEdgeAttribute, QueryGraphEdgeHandle, QueryGraphNodes } from './model';
+
+const metaAttribute: Record<string, QueryGraphEdgeAttribute> = {
+  '(# Connection)': {
+    attributeName: '(# Connection)',
+    attributeType: 'float',
+    attributeDimension: 'numerical',
+  },
+};
+
+export function checkForMetaAttributes(graphologyAttributes: QueryGraphNodes): QueryGraphEdgeHandle[] {
+  const ret: QueryGraphEdgeHandle[] = [];
+  const defaultHandleData = {
+    nodeId: graphologyAttributes.id,
+    nodeName: graphologyAttributes.name || '',
+    nodeType: graphologyAttributes.type,
+    handleType: graphologyAttributes.type === QueryElementTypes.Entity ? Handles.EntityAttribute : Handles.RelationAttribute,
+  };
+
+  // Only include if not already there
+  const metaAttributesToInclude = Object.keys(metaAttribute).filter((attributeName) => !(attributeName in graphologyAttributes.attributes));
+  return metaAttributesToInclude.map((attributeName) => ({
+    ...defaultHandleData,
+    ...metaAttribute[attributeName],
+  })) as QueryGraphEdgeHandle[];
+}
diff --git a/libs/shared/lib/querybuilder/model/graphology/model.ts b/libs/shared/lib/querybuilder/model/graphology/model.ts
index dc4a2bc1a42ebfa4cc9a2f823458dd3fa4a1cd42..b47deeb6e08999538cef80e4c2d163a78125eda8 100644
--- a/libs/shared/lib/querybuilder/model/graphology/model.ts
+++ b/libs/shared/lib/querybuilder/model/graphology/model.ts
@@ -23,7 +23,7 @@ export type NodeDefaults = {
   type: QueryElementTypes;
   width?: number;
   height?: number;
-  attributes?: NodeAttribute[];
+  attributes: NodeAttribute[];
   selected?: boolean;
 };
 
@@ -33,6 +33,7 @@ export interface EntityData {
   leftRelationHandleId?: QueryGraphEdgeHandle;
   rightRelationHandleId?: QueryGraphEdgeHandle;
   selected?: boolean;
+  type: QueryElementTypes.Entity;
 }
 
 /** Interface for the data in an relation node. */
@@ -44,6 +45,7 @@ export interface RelationData {
   rightEntityHandleId?: QueryGraphEdgeHandle;
   direction?: 'left' | 'right' | 'both';
   selected?: boolean;
+  type: QueryElementTypes.Relation;
 }
 
 export interface LogicData {
@@ -53,18 +55,19 @@ export interface LogicData {
   // key: string;
   logic: GeneralDescription<AllLogicTypes>;
   inputs: Record<string, InputNodeTypeTypes>; // name from InputNode -> InputNodeTypeTypes
+  type: QueryElementTypes.Logic;
 }
 
-export type EntityNodeAttributes = XYPosition & EntityData & NodeDefaults;
-export type RelationNodeAttributes = XYPosition & RelationData & NodeDefaults;
-export type LogicNodeAttributes = XYPosition & LogicData & NodeDefaults;
+export type EntityNodeAttributes = XYPosition & NodeDefaults & EntityData;
+export type RelationNodeAttributes = XYPosition & NodeDefaults & RelationData;
+export type LogicNodeAttributes = XYPosition & NodeDefaults & LogicData;
 
 export type QueryGraphNodes = EntityNodeAttributes | RelationNodeAttributes | LogicNodeAttributes;
 
 export type QueryGraphEdgeAttribute = {
-  attributeName?: string;
-  attributeType?: InputNodeType;
-  attributeDimension?: InputNodeDimension;
+  attributeName: string;
+  attributeType: InputNodeType;
+  attributeDimension: InputNodeDimension;
 };
 
 export type QueryGraphEdgeHandle = {
@@ -72,7 +75,7 @@ export type QueryGraphEdgeHandle = {
   nodeName: string;
   nodeType: QueryElementTypes;
   handleType: Handles;
-} & QueryGraphEdgeAttribute;
+} & Partial<QueryGraphEdgeAttribute>;
 
 export type QueryGraphEdges = {
   type: string;
@@ -80,10 +83,6 @@ export type QueryGraphEdges = {
   targetHandleData: QueryGraphEdgeHandle;
 };
 
-export type QueryGraphEdgesOpt = {
-  type?: string;
-  sourceHandleData?: QueryGraphEdgeHandle;
-  targetHandleData?: QueryGraphEdgeHandle;
-};
+export type QueryGraphEdgesOpt = Partial<QueryGraphEdges>;
 
 // export class QueryGraph extends Graph<QueryGraphNodes, GAttributes, GAttributes>; // is in utils.ts
diff --git a/libs/shared/lib/querybuilder/model/graphology/utils.ts b/libs/shared/lib/querybuilder/model/graphology/utils.ts
index 041fe0cde310d5a3a9ab8b2b9056c66d86f14015..f08865788e95edfd3ffd42c6ae8a4002f2e4dae2 100644
--- a/libs/shared/lib/querybuilder/model/graphology/utils.ts
+++ b/libs/shared/lib/querybuilder/model/graphology/utils.ts
@@ -4,7 +4,6 @@ import { Attributes as GAttributes, Attributes, SerializedGraph } from 'grapholo
 import {
   EntityNodeAttributes,
   LogicNodeAttributes,
-  QueryGraphEdgeAttribute,
   QueryGraphEdgeHandle,
   QueryGraphEdges,
   QueryGraphEdgesOpt,
@@ -15,6 +14,7 @@ import { XYPosition } from 'reactflow';
 import { Handles, QueryElementTypes } from '../reactflow';
 import { SchemaAttribute, SchemaAttributeTypes } from '@graphpolaris/shared/lib/schema';
 import { InputNodeType, InputNodeTypeTypes } from '../logic/general';
+import { checkForMetaAttributes } from './metaAttributes';
 
 /** monospace fontsize table */
 const widthPerFontsize = {
@@ -54,6 +54,9 @@ export class QueryMultiGraphology extends Graph<QueryGraphNodes, QueryGraphEdges
 
     if (!attributes.id) attributes.id = 'id_' + (Date.now() + Math.floor(Math.random() * 1000)).toString();
 
+    // Add to the beginning the meta attributes, such as (# Connection)
+    attributes.attributes = [...checkForMetaAttributes(attributes).map((a) => ({ handleData: a })), ...attributes.attributes];
+
     return attributes;
   }
 
@@ -113,19 +116,17 @@ export class QueryMultiGraphology extends Graph<QueryGraphNodes, QueryGraphEdges
     return attributes;
   }
 
-  public addLogicPill2Graphology(attributes: QueryGraphNodes, inputValues: Record<string, InputNodeTypeTypes> = {}): QueryGraphNodes {
-    attributes = this.configureDefaults(attributes);
-    if (!attributes.type) attributes.type = QueryElementTypes.Logic;
+  public addLogicPill2Graphology(attributes: LogicNodeAttributes, inputValues: Record<string, InputNodeTypeTypes> = {}): QueryGraphNodes {
+    attributes = this.configureDefaults(attributes) as LogicNodeAttributes;
     if (!attributes.name || !attributes.id) throw Error('type or name is not defined');
 
     // add default inputs, but only if not there yet
     if (attributes.type === QueryElementTypes.Logic) {
-      if ((attributes as LogicNodeAttributes).inputs === undefined) {
-        attributes = attributes as LogicNodeAttributes;
-        (attributes as LogicNodeAttributes).logic.inputs.forEach((input, i) => {
+      if (attributes.inputs === undefined || Object.keys(attributes.inputs).length === 0) {
+        attributes.logic.inputs.forEach((input, i) => {
           // Setup default non-linked inputs as regular values matching the input expected type
-          if (!(attributes as LogicNodeAttributes).inputs) (attributes as LogicNodeAttributes).inputs = {};
-          (attributes as LogicNodeAttributes).inputs[input.name] = inputValues?.[input.name] || input.default;
+          if (!attributes.inputs) attributes.inputs = {};
+          attributes.inputs[input.name] = inputValues?.[input.name] || input.default;
         });
         // (attributes as LogicNodeAttributes).leftEntityHandleId = getHandleId(attributes.id, name, type, Handles.RelationLeft, '');
         // (attributes as LogicNodeAttributes).rightEntityHandleId = getHandleId(attributes.id, name, type, Handles.RelationRight, '');
diff --git a/libs/shared/lib/querybuilder/model/reactflow/utils.ts b/libs/shared/lib/querybuilder/model/reactflow/utils.ts
index b8a0dd7913527737b527ede89bd5d96d80c884cd..7ee9c55c078ee19fdc957b43d1efa4c220f1c756 100644
--- a/libs/shared/lib/querybuilder/model/reactflow/utils.ts
+++ b/libs/shared/lib/querybuilder/model/reactflow/utils.ts
@@ -4,7 +4,7 @@ import { toHandleId } from '..';
 
 // Takes the querybuilder graph as an input and creates react flow elements for them.
 export function createReactFlowElements<T extends Graph>(
-  graph: T
+  graph: T,
 ): {
   nodes: Array<Node>;
   edges: Array<Edge>;
@@ -13,8 +13,6 @@ export function createReactFlowElements<T extends Graph>(
   const edges: Array<Edge> = [];
 
   graph.forEachNode((node, attributes): void => {
-    // console.log('attributes', attributes);
-
     let position = { x: attributes?.x || 0, y: attributes?.y || 0 };
     const RFNode: Node<typeof attributes> = {
       id: node,
@@ -28,8 +26,6 @@ export function createReactFlowElements<T extends Graph>(
   // Add the reactflow edges
   graph.forEachEdge((edge, attributes, source, target): void => {
     // connection from attributes don't have visible connection lines
-    // if (attributes.type == 'attribute_connection') return;
-
     const RFEdge: Edge<typeof attributes> = {
       id: edge,
       source: source,
@@ -43,7 +39,5 @@ export function createReactFlowElements<T extends Graph>(
     edges.push(RFEdge);
   });
 
-  // console.log('nodes', nodes, 'edges', edges);
-
   return { nodes, edges };
 }
diff --git a/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx b/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx
index 26da1edfb41b03e3e960c6d7ee7e1acf8b5028fc..a54e5e213aba9371059578c3a8d60269755d8d8f 100644
--- a/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx
+++ b/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx
@@ -195,6 +195,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => {
             y: position.y - mouse_y,
             name: dragData.name,
             schemaKey: dragData.name,
+            attributes: [],
           },
           schema.getNodeAttribute(dragData.name, 'attributes'),
         );
@@ -212,6 +213,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => {
             name: dragData.collection,
             schemaKey: dragData.label,
             collection: dragData.collection,
+            attributes: [],
           },
           schema.getEdgeAttribute(dragData.label, 'attributes'),
         );
@@ -238,6 +240,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => {
                 y: position.y,
                 name: fromNodeID,
                 schemaKey: fromNodeID,
+                attributes: [],
               },
               schema.getNodeAttribute(fromNodeID, 'attributes'),
             );
@@ -249,6 +252,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => {
                 y: position.y,
                 name: toNodeID,
                 schemaKey: toNodeID,
+                attributes: [],
               },
               schema.getNodeAttribute(toNodeID, 'attributes'),
             );
@@ -280,6 +284,8 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => {
           x: position.x,
           y: position.y,
           logic: logic,
+          attributes: [],
+          inputs: {},
         });
 
         dispatch(setQuerybuilderGraphology(graphologyGraph));
diff --git a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx
index 041acb8dfad4987c3d2863f57333983d0243ecde..0b9f7cff881741335e9413acaf28882b0b38eba6 100644
--- a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx
+++ b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx
@@ -86,6 +86,8 @@ export const QueryBuilderLogicPillsPanel = (props: {
         x: bounds.width / 2,
         y: bounds.height / 2,
         logic: logic,
+        attributes: [],
+        inputs: {},
       });
     } else {
       const params = props.connection.params;
@@ -97,6 +99,8 @@ export const QueryBuilderLogicPillsPanel = (props: {
         x: position.x,
         y: position.y,
         logic: logic,
+        attributes: [],
+        inputs: {},
       });
 
       if (!logicNode?.id) throw new Error('Logic node has no id');
diff --git a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderRelatedNodesPanel.tsx b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderRelatedNodesPanel.tsx
index 3b57002c3b1a5fc19656a596182ecd959f5e6425..5b398a8d50a65ec8cc45697e1bd2dd78950dbdac 100644
--- a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderRelatedNodesPanel.tsx
+++ b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderRelatedNodesPanel.tsx
@@ -91,6 +91,7 @@ export const QueryBuilderRelatedNodesPanel = (props: {
         y: position.y,
         name: entity.name,
         schemaKey: entity.name,
+        attributes: [],
       },
       schemaGraph.getNodeAttribute(entity.name, 'attributes'),
     );
@@ -124,6 +125,7 @@ export const QueryBuilderRelatedNodesPanel = (props: {
         depth: { min: queryBuilderSettings.depth.min, max: queryBuilderSettings.depth.max },
         name: relation.collection,
         collection: relation.collection,
+        attributes: [],
       },
       schemaGraph.getEdgeAttribute(relation.label, 'attributes'),
     );
diff --git a/libs/shared/lib/querybuilder/pills/customFlowPills/relationpill/QueryRelationPill.tsx b/libs/shared/lib/querybuilder/pills/customFlowPills/relationpill/QueryRelationPill.tsx
index 3bb9e75d3b2a75f6547594fc47946df45407dfb7..1fd01d879868d91cffd1051af362c58e97eea402 100644
--- a/libs/shared/lib/querybuilder/pills/customFlowPills/relationpill/QueryRelationPill.tsx
+++ b/libs/shared/lib/querybuilder/pills/customFlowPills/relationpill/QueryRelationPill.tsx
@@ -62,10 +62,6 @@ export const QueryRelationPill = memo((node: SchemaReactflowRelationNode) => {
   //   dispatch(setQuerybuilderGraphology(graphologyGraph));
   // };
 
-  const calcWidth = (data: number) => {
-    return data.toString().length + 0.5 + 'ch';
-  };
-
   return (
     <div className="w-fit h-fit p-3 bg-transparent nowheel">
       <RelationPill
@@ -84,55 +80,6 @@ export const QueryRelationPill = memo((node: SchemaReactflowRelationNode) => {
               }}
               className={openDropdown ? 'border-secondary-200' : ''}
             />
-            {/* <span className="pr-1">
-                  <span> [</span>
-                  <input
-                    className={
-                      'bg-inherit text-center appearance-none mx-0.1 rounded-sm ' +
-                      (depth.min < 0 || depth.min > depth.max ? ' bg-danger-400 ' : '')
-                    }
-                    style={{ maxWidth: calcWidth(depth.min) }}
-                    type="number"
-                    min={0}
-                    placeholder={'?'}
-                    value={depth.min}
-                    onChange={(e) => {
-                      setDepth({ ...depth, min: parseInt(e.target.value) });
-                    }}
-                    onBlur={(e) => {
-                      onNodeUpdated();
-                    }}
-                    onKeyDown={(e) => {
-                      if (e.key === 'Enter') {
-                        onNodeUpdated();
-                      }
-                    }}
-                  ></input>
-                  <span>..</span>
-                  <input
-                    className={
-                      'bg-inherit text-center appearance-none mx-0.1 rounded-sm ' +
-                      (depth.max > 99 || depth.min > depth.max ? ' bg-danger-400 ' : '')
-                    }
-                    style={{ maxWidth: calcWidth(depth.max) }}
-                    type="number"
-                    min={1}
-                    placeholder={'?'}
-                    value={depth.max}
-                    onChange={(e) => {
-                      setDepth({ ...depth, max: parseInt(e.target.value) });
-                    }}
-                    onBlur={(e) => {
-                      onNodeUpdated();
-                    }}
-                    onKeyDown={(e) => {
-                      if (e.key === 'Enter') {
-                        onNodeUpdated();
-                      }
-                    }}
-                  ></input>
-                  <span>]</span>
-                </span> */}
           </div>
         }
         withHandles="horizontal"
@@ -155,15 +102,13 @@ export const QueryRelationPill = memo((node: SchemaReactflowRelationNode) => {
           ></Handle>
         }
       >
-        {data?.attributes && (
-          <PillDropdown
-            node={node}
-            attributes={data.attributes}
-            attributeEdges={attributeEdges.map((edge) => edge?.attributes)}
-            open={openDropdown}
-            mr={-pillWidth * 0.05}
-          />
-        )}
+        <PillDropdown
+          node={node}
+          attributes={data?.attributes || []}
+          attributeEdges={attributeEdges.map((edge) => edge?.attributes)}
+          open={openDropdown}
+          mr={-pillWidth * 0.05}
+        />
       </RelationPill>
     </div>
   );
diff --git a/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdown.tsx b/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdown.tsx
index 07caaabbf76bed3384b3992afe6a4a15f0102242..0868585845f4df0ac04de36f8d7fe5887fab34c5 100644
--- a/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdown.tsx
+++ b/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdown.tsx
@@ -1,17 +1,21 @@
 import { useMemo, ReactElement, useState, useContext } from 'react';
-import { NodeAttribute, QueryGraphEdges, SchemaReactflowEntityNode, handleDataFromReactflowToDataId, toHandleId } from '../../model';
-import { Handle, Position, useUpdateNodeInternals } from 'reactflow';
+import {
+  Handles,
+  NodeAttribute,
+  QueryElementTypes,
+  QueryGraphEdges,
+  SchemaReactflowEntityNode,
+  SchemaReactflowRelationNode,
+} from '../../model';
 import { Abc, CalendarToday, Map, Numbers, Place, QuestionMarkOutlined } from '@mui/icons-material';
-import { Icon } from '@graphpolaris/shared/lib/components/icon';
-import { PillHandle } from '@graphpolaris/shared/lib/components/pills/PillHandle';
-import { pillDropdownPadding } from '@graphpolaris/shared/lib/components/pills/pill.const';
 import { Button, TextInput, useAppDispatch, useQuerybuilderAttributesShown } from '../../..';
 import { attributeShownToggle } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
 import { isEqual } from 'lodash-es';
 import { QueryBuilderDispatcherContext } from '../../panel/QueryBuilderDispatcher';
+import { PillDropdownItem } from './PillDropdownItem';
 
 type PillDropdownProps = {
-  node: SchemaReactflowEntityNode;
+  node: SchemaReactflowEntityNode | SchemaReactflowRelationNode;
   attributes: NodeAttribute[];
   attributeEdges: (QueryGraphEdges | undefined)[];
   open: boolean;
@@ -36,7 +40,6 @@ export const PillDropdown = (props: PillDropdownProps) => {
   const [filter, setFilter] = useState<string>('');
   const dispatch = useAppDispatch();
   const attributesBeingShown = useQuerybuilderAttributesShown();
-  const { openLogicPillCreate } = useContext(QueryBuilderDispatcherContext);
 
   const attributesOfInterest = useMemo(() => {
     return props.attributes.map((attribute) =>
@@ -48,58 +51,22 @@ export const PillDropdown = (props: PillDropdownProps) => {
     <div className={'border-[1px] border-secondary-200 divide-y divide-secondary-200 !z-50'}>
       {attributesOfInterest &&
         attributesOfInterest.map((showing, i) => {
-          if (showing === false) return null;
-
-          const attribute = props.attributes[i];
-          if (attribute.handleData.attributeName === undefined) {
-            throw new Error('attribute.handleData.attributeName is undefined');
-          }
-
-          const handleId = toHandleId(handleDataFromReactflowToDataId(props.node, attribute));
-          const handleType = 'source';
-
+          if (!showing) return null;
           return (
-            <div
-              className="px-2 py-1 bg-secondary-100 flex justify-between items-center"
-              key={(attribute.handleData.attributeName || '') + i}
-            >
-              <p className="truncate text-[0.6rem]">{attribute.handleData.attributeName}</p>
-              <Button
-                variantType="secondary"
-                variant="ghost"
-                size="2xs"
-                iconComponent={
-                  attribute.handleData?.attributeDimension ? IconMap[attribute.handleData.attributeDimension] : <QuestionMarkOutlined />
-                }
-                onClick={() => {
-                  openLogicPillCreate(
-                    {
-                      nodeId: props.node.id,
-                      handleId: handleId,
-                      handleType: handleType,
-                    },
-                    {
-                      x: props.node.xPos + 200,
-                      y: props.node.yPos + 50,
-                    },
-                  );
-                }}
-              />
-              <PillHandle
-                mr={-pillDropdownPadding + (props.mr || 0)}
-                handleTop="auto"
-                position={Position.Right}
-                className={`stroke-white${props.className ? ` ${props.className}` : ''}`}
-                type="square"
-              >
-                <Handle
-                  id={handleId}
-                  type={handleType}
-                  position={Position.Right}
-                  className={'!rounded-none !bg-transparent !w-full !h-full !right-0 !left-0 !border-0'}
-                ></Handle>
-              </PillHandle>
-            </div>
+            <PillDropdownItem
+              key={props.attributes[i].handleData.attributeName || i}
+              node={props.node}
+              attribute={props.attributes[i]}
+              mr={props.mr}
+              className={props.className}
+              icon={
+                props.attributes[i].handleData?.attributeDimension ? (
+                  IconMap[props.attributes[i].handleData.attributeDimension || 0]
+                ) : (
+                  <QuestionMarkOutlined />
+                )
+              }
+            />
           );
         })}
       {(props.open || forceOpen) && (
diff --git a/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdownItem.tsx b/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdownItem.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..6304229d14cbdff0438f6d2b60c623002456171a
--- /dev/null
+++ b/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdownItem.tsx
@@ -0,0 +1,71 @@
+import { ReactElement, useContext } from 'react';
+import {
+  NodeAttribute,
+  SchemaReactflowEntityNode,
+  SchemaReactflowRelationNode,
+  handleDataFromReactflowToDataId,
+  toHandleId,
+} from '../../model';
+import { Handle, Position } from 'reactflow';
+import { PillHandle } from '@graphpolaris/shared/lib/components/pills/PillHandle';
+import { pillDropdownPadding } from '@graphpolaris/shared/lib/components/pills/pill.const';
+import { Button } from '../../..';
+import { QueryBuilderDispatcherContext } from '../../panel/QueryBuilderDispatcher';
+
+type PillDropdownItemProps = {
+  attribute: NodeAttribute;
+  node: SchemaReactflowEntityNode | SchemaReactflowRelationNode;
+  className?: string;
+  mr?: number;
+  icon: ReactElement;
+};
+
+export const PillDropdownItem = (props: PillDropdownItemProps) => {
+  const { openLogicPillCreate } = useContext(QueryBuilderDispatcherContext);
+
+  if (props.attribute.handleData.attributeName === undefined) {
+    throw new Error('attribute.handleData.attributeName is undefined');
+  }
+
+  const handleId = toHandleId(handleDataFromReactflowToDataId(props.node, props.attribute));
+  const handleType = 'source';
+
+  return (
+    <div className="px-2 py-1 bg-secondary-100 flex justify-between items-center">
+      <p className="truncate text-[0.6rem]">{props.attribute.handleData.attributeName}</p>
+      <Button
+        variantType="secondary"
+        variant="ghost"
+        size="2xs"
+        iconComponent={props.icon}
+        onClick={() => {
+          openLogicPillCreate(
+            {
+              nodeId: props.node.id,
+              handleId: handleId,
+              handleType: handleType,
+            },
+            {
+              x: props.node.xPos + 200,
+              y: props.node.yPos + 50,
+            },
+          );
+        }}
+      />
+      <PillHandle
+        mr={-pillDropdownPadding + (props.mr || 0)}
+        handleTop="auto"
+        position={Position.Right}
+        className={`stroke-white${props.className ? ` ${props.className}` : ''}`}
+        type="square"
+      >
+        <Handle
+          id={handleId}
+          type={handleType}
+          position={Position.Right}
+          className={'!rounded-none !bg-transparent !w-full !h-full !right-0 !left-0 !border-0'}
+        ></Handle>
+      </PillHandle>
+    </div>
+  );
+};
diff --git a/libs/shared/lib/querybuilder/query-utils/query2backend.spec.ts b/libs/shared/lib/querybuilder/query-utils/query2backend.spec.ts
index a2ed912b992d56b664adc30a5bf22b9dda77477a..8b35dba9498b26054d57f7706d4792ca838a1693 100644
--- a/libs/shared/lib/querybuilder/query-utils/query2backend.spec.ts
+++ b/libs/shared/lib/querybuilder/query-utils/query2backend.spec.ts
@@ -14,6 +14,7 @@ const defaultQuery = {
   query: [],
   limit: 500,
   return: ['*'],
+  machineLearning: [],
 };
 
 const defaultSettings: QueryBuilderSettings = {
@@ -38,6 +39,7 @@ describe('QueryUtils Entity and Relations', () => {
       x: 100,
       y: 100,
       name: 'Airport 1',
+      attributes: [],
     });
     const entity2 = graph.addPill2Graphology({
       id: '10',
@@ -45,6 +47,7 @@ describe('QueryUtils Entity and Relations', () => {
       x: 200,
       y: 200,
       name: 'Airport 2',
+      attributes: [],
     });
 
     const relation1 = graph.addPill2Graphology({
@@ -55,6 +58,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(entity1, relation1);
@@ -90,8 +94,8 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run multiple path query translation', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2' });
+    const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -101,13 +105,14 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1, { type: 'connection' });
     graph.addEdge2Graphology(r1, e2, { type: 'connection' });
 
-    const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12' });
-    const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22' });
+    const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12', attributes: [] });
+    const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22', attributes: [] });
 
     const r12 = graph.addPill2Graphology({
       id: 'r12',
@@ -117,6 +122,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports 2',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e12, r12);
@@ -169,10 +175,10 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run one relation multiple entity query translation', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2' });
-    const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12' });
-    const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22' });
+    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2', attributes: [] });
+    const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12', attributes: [] });
+    const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -182,6 +188,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1);
@@ -235,10 +242,10 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run lone entities query translation', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2' });
-    const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12' });
-    const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22' });
+    const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2', attributes: [] });
+    const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12', attributes: [] });
+    const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -248,6 +255,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1);
@@ -276,8 +284,8 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run lone relations query translation', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2' });
+    const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -287,6 +295,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
     const r2 = graph.addPill2Graphology({
       id: 'r2',
@@ -296,6 +305,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports 2',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1);
@@ -326,7 +336,7 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run relation only left side connected query translation', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
+    const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -336,6 +346,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1);
@@ -361,7 +372,7 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run relation only right side connected query translation', () => {
     const graph = new QueryMultiGraphology();
 
-    const e2 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 2' });
+    const e2 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 2', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -371,6 +382,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(r1, e2);
@@ -394,8 +406,8 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run entity and relations multi connection', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 2' });
+    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 2', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -405,6 +417,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     const r2 = graph.addPill2Graphology({
@@ -415,6 +428,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports 2',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1);
@@ -451,7 +465,7 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run in case of loops', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
+    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -461,6 +475,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1, { type: 'connection' });
@@ -487,8 +502,8 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run in case of loops and regular', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
+    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -498,6 +513,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1, { type: 'connection' });
@@ -538,8 +554,8 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run in case of loops and regular left', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
+    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
 
     const r1 = graph.addPill2Graphology({
       id: 'r1',
@@ -549,6 +565,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(e1, r1, { type: 'connection' });
@@ -584,8 +601,8 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run in case of direct entity connection', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
+    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
 
     graph.addEdge2Graphology(e1, e2, { type: 'connection' });
 
@@ -618,6 +635,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     const r2 = graph.addPill2Graphology({
@@ -628,6 +646,7 @@ describe('QueryUtils Entity and Relations', () => {
       name: 'Flight between airports 2',
       collection: 'Relation Pill',
       depth: { min: 0, max: 1 },
+      attributes: [],
     });
 
     graph.addEdge2Graphology(r1, r2, { type: 'connection' });
@@ -656,8 +675,8 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run in case of entity only loop', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
-    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
+    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
+    const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
 
     graph.addEdge2Graphology(e1, e2, { type: 'connection' });
     graph.addEdge2Graphology(e2, e1, { type: 'connection' });
@@ -691,7 +710,7 @@ describe('QueryUtils Entity and Relations', () => {
   it('should run in case of entity only self loop', () => {
     const graph = new QueryMultiGraphology();
 
-    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' });
+    const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] });
 
     graph.addEdge2Graphology(e1, e1, { type: 'connection' });
 
@@ -721,6 +740,7 @@ describe('QueryUtils calculateQueryLogic', () => {
         x: 100,
         y: 100,
         name: 'Airport 1',
+        attributes: [],
       },
       [{ name: 'age', type: 'string' }],
     );
@@ -732,6 +752,8 @@ describe('QueryUtils calculateQueryLogic', () => {
       y: 100,
       name: 'Logic 1',
       logic: MathFilters[NumberFilterTypes.EQUAL],
+      attributes: [],
+      inputs: {},
     });
 
     graph.addEdge2Graphology(e1, l1, { type: 'connection' }, { sourceHandleName: 'age', targetHandleName: '1' });
@@ -754,6 +776,7 @@ describe('QueryUtils with Logic', () => {
         x: 100,
         y: 100,
         name: 'Airport 1',
+        attributes: [],
       },
       [{ name: 'age', type: 'string' }],
     );
@@ -765,6 +788,8 @@ describe('QueryUtils with Logic', () => {
       y: 100,
       name: 'Logic 1',
       logic: MathFilters[NumberFilterTypes.EQUAL],
+      attributes: [],
+      inputs: {},
     });
 
     graph.addEdge2Graphology(e1, l1, { type: 'connection' }, { sourceHandleName: 'age', targetHandleName: 'Value' });
@@ -800,6 +825,7 @@ describe('QueryUtils with Logic', () => {
         x: 100,
         y: 100,
         name: 'Airport 1',
+        attributes: [],
       },
       [{ name: 'age', type: 'string' }],
     );
@@ -811,6 +837,7 @@ describe('QueryUtils with Logic', () => {
         x: 100,
         y: 100,
         name: 'Airport 2',
+        attributes: [],
       },
       [{ name: 'age', type: 'string' }],
     );
@@ -822,6 +849,8 @@ describe('QueryUtils with Logic', () => {
       y: 100,
       name: 'Filter EQ',
       logic: MathFilters[NumberFilterTypes.EQUAL],
+      attributes: [],
+      inputs: {},
     });
 
     const l2 = graph.addLogicPill2Graphology({
@@ -831,6 +860,8 @@ describe('QueryUtils with Logic', () => {
       y: 100,
       name: 'Logic ADD',
       logic: NumberFunctions[NumberFunctionTypes.ADD],
+      attributes: [],
+      inputs: {},
     });
 
     graph.addEdge2Graphology(e1, l2, { type: 'connection' }, { sourceHandleName: 'age', targetHandleName: 'Value' });
@@ -876,6 +907,7 @@ describe('QueryUtils with Logic', () => {
         x: 100,
         y: 100,
         name: 'Airport 1',
+        attributes: [],
       },
       [{ name: 'age', type: 'string' }],
     );
@@ -887,6 +919,8 @@ describe('QueryUtils with Logic', () => {
       y: 100,
       name: 'Logic LT',
       logic: MathFilters[NumberFilterTypes.LESS_THAN],
+      attributes: [],
+      inputs: {},
     });
 
     const l2 = graph.addLogicPill2Graphology({
@@ -896,6 +930,8 @@ describe('QueryUtils with Logic', () => {
       y: 100,
       name: 'Logic average',
       logic: MathAggregations[NumberAggregationTypes.AVG],
+      attributes: [],
+      inputs: {},
     });
 
     graph.addEdge2Graphology(e1, l2, { type: 'connection' }, { sourceHandleName: 'age', targetHandleName: 'Value' });
@@ -932,6 +968,7 @@ describe('QueryUtils with Logic', () => {
         x: 100,
         y: 100,
         name: 'Airport 1',
+        attributes: [],
       },
       [{ name: 'age', type: 'string' }],
     );
@@ -944,6 +981,8 @@ describe('QueryUtils with Logic', () => {
         y: 100,
         name: 'Logic LT',
         logic: MathFilters[NumberFilterTypes.LESS_THAN],
+        attributes: [],
+        inputs: {},
       },
       { '1': 5 },
     );
@@ -982,6 +1021,7 @@ it('should no connections between entities and relations', () => {
       x: 100,
       y: 100,
       name: 'Airport 1',
+      attributes: [],
     },
     [{ name: 'age', type: 'string' }],
   );
@@ -993,6 +1033,7 @@ it('should no connections between entities and relations', () => {
       x: 100,
       y: 100,
       name: 'Airport 2',
+      attributes: [],
     },
     [{ name: 'age', type: 'string' }],
   );
@@ -1004,6 +1045,8 @@ it('should no connections between entities and relations', () => {
       y: 100,
       name: 'Relation 1',
       depth: { min: 0, max: 1 },
+      attributes: [],
+      collection: 'r',
     },
     [{ name: 'age', type: 'string' }],
   );
diff --git a/libs/shared/lib/querybuilder/query-utils/query2backend.ts b/libs/shared/lib/querybuilder/query-utils/query2backend.ts
index 92fd9e6f2c4a21c6150f05f6f1969adbcb88db89..f04b9f1cf72eddc9e47b1308d97d007400dcf044 100644
--- a/libs/shared/lib/querybuilder/query-utils/query2backend.ts
+++ b/libs/shared/lib/querybuilder/query-utils/query2backend.ts
@@ -31,7 +31,7 @@ const traverseEntityRelationPaths = (
     // console.log('new path');
     paths.push([]);
     if (node.attributes.type === QueryElementTypes.Relation) {
-      paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.y });
+      paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.y, attributes: [] });
     }
   } else if (paths[currentIdx].length > 0) {
     const lastNode = paths[currentIdx][paths[currentIdx].length - 1];
@@ -39,13 +39,15 @@ const traverseEntityRelationPaths = (
       if (lastNode.type === QueryElementTypes.Entity) {
         paths[currentIdx].push({
           type: QueryElementTypes.Relation,
+          collection: node.key,
           x: node.attributes.x,
           y: node.attributes.x,
           depth: { min: settings.depth.min, max: settings.depth.max },
           direction: 'both',
+          attributes: [],
         });
       } else {
-        paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.x });
+        paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.x, attributes: [] });
       }
     }
   }
@@ -59,7 +61,7 @@ const traverseEntityRelationPaths = (
   let connections = edges.filter((e) => e.source === node.key);
   if (connections.length === 0) {
     if (node.attributes.type === QueryElementTypes.Relation) {
-      paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.x });
+      paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.x, attributes: [] });
     }
     return 0;
   }
@@ -139,6 +141,9 @@ export function calculateQueryLogic(
         if (!connectionToInputRef.attributes?.sourceHandleData)
           throw Error('Malformed Graph! Logic node is connected but has no sourceHandleData');
         // Is connected to entity or relation node
+        if (connectionToInputRef.attributes.sourceHandleData.attributeName === '(# Connection)') {
+          return ['Count', `@${connectionToInputRef.attributes.sourceHandleData.nodeId}`];
+        }
         return `@${connectionToInputRef.attributes.sourceHandleData.nodeId}.${connectionToInputRef.attributes.sourceHandleData.attributeName}`;
       }
     } else {
diff --git a/libs/shared/lib/vis/components/config/SelectionConfig.tsx b/libs/shared/lib/vis/components/config/SelectionConfig.tsx
index 7d41cf4a15e61c3a5d3dfb8ab41cf2a7021445e4..1d5e96f046c6b5255e4b6ac3f8862924d610bdee 100644
--- a/libs/shared/lib/vis/components/config/SelectionConfig.tsx
+++ b/libs/shared/lib/vis/components/config/SelectionConfig.tsx
@@ -1,3 +1,4 @@
+import React from 'react';
 import { SelectionStateI, unSelect } from '@graphpolaris/shared/lib/data-access/store/interactionSlice';
 import { Delete } from '@mui/icons-material';
 import { useDispatch } from 'react-redux';
@@ -25,8 +26,8 @@ export const SelectionConfig = () => {
         />
       </div>
       {selection.content.map((item, index) => (
-        <>
-          <div key={index + 'id'} className="flex justify-between items-center px-4 py-1 gap-1">
+        <React.Fragment key={index + 'id'}>
+          <div className="flex justify-between items-center px-4 py-1 gap-1">
             <span className="text-xs font-normal">ID</span>
             <span className="text-xs">{item._id}</span>
           </div>
@@ -43,7 +44,7 @@ export const SelectionConfig = () => {
               </div>
             );
           })}
-        </>
+        </React.Fragment>
       ))}
     </div>
   );
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLMachineLearning.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLMachineLearning.tsx
index 78d36400c8efd19494d706d1e84a56ad86c1d62d..19c50b62913aa5d8551f7f57e2714792d2ca3946 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLMachineLearning.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLMachineLearning.tsx
@@ -6,18 +6,18 @@ export function processLinkPrediction(ml: ML, graph: GraphType): GraphType {
   if (ml === undefined || ml.linkPrediction === undefined) return graph;
 
   if (ml.linkPrediction.enabled) {
-    let allNodeIds = new Set(graph.nodes.map((n) => n._id));
+    let allNodeIds = new Set(Object.keys(graph.nodes));
     ml.linkPrediction.result.forEach((link) => {
       if (allNodeIds.has(link.from) && allNodeIds.has(link.to)) {
         const toAdd: LinkType = {
-          id: link.from + link.to,
+          id: link.from + ':LP:' + link.to, // TODO: this only supports one link between two nodes
           source: link.from,
           target: link.to,
           value: link.attributes.jaccard_coefficient as number,
           mlEdge: true,
           color: 0x000000,
         };
-        graph.links.push(toAdd);
+        graph.links[toAdd.id] = toAdd;
       }
     });
   }
@@ -35,18 +35,16 @@ export function processCommunityDetection(ml: ML, graph: GraphType): GraphType {
       });
     });
 
-    graph.nodes = graph.nodes.map((node, i) => {
-      if (allNodeIdMap.has(node._id)) {
-        node.cluster = allNodeIdMap.get(node._id);
+    Object.keys(graph.nodes).forEach((nodeId) => {
+      if (allNodeIdMap.has(nodeId)) {
+        graph.nodes[nodeId].cluster = allNodeIdMap.get(nodeId);
       } else {
-        node.cluster = -1;
+        graph.nodes[nodeId].cluster = -1;
       }
-      return node;
     });
   } else {
-    graph.nodes = graph.nodes.map((node, i) => {
-      node.cluster = undefined;
-      return node;
+    Object.keys(graph.nodes).forEach((nodeId) => {
+      graph.nodes[nodeId].cluster = undefined;
     });
   }
   return graph;
@@ -101,6 +99,7 @@ export const useNLMachineLearning = (props: {
    * Gets the edges corresponding to the shortestPath.
    * @param pathString The path as a string.
    * @returns The path as a LinkType[]
+   * @deprecated This function is not working anymore
    */
   function getShortestPathEdges(pathString: string[]): LinkType[] {
     try {
@@ -112,13 +111,14 @@ export const useNLMachineLearning = (props: {
           continue;
         }
         let edgeFound = false;
-        props.graph.links.forEach((link: any) => {
-          const { source, target } = link;
+        Object.keys(props.graph.links).forEach((key) => {
+          const link = props.graph.links[key];
           if (
-            (pathString[index] == source.id && pathString[index + 1] == target.id) ||
-            (pathString[index] == source && pathString[index + 1] == target) ||
-            (pathString[index + 1] == source.id && pathString[index] == target.id) ||
-            (pathString[index + 1] == source && pathString[index] == target)
+            false // FIXME: This is not working anymore
+            // (pathString[index] == source.id && pathString[index + 1] == target.id) ||
+            // (pathString[index] == source && pathString[index + 1] == target) ||
+            // (pathString[index + 1] == source.id && pathString[index] == target.id) ||
+            // (pathString[index + 1] == source && pathString[index] == target)
           ) {
             newPath.push(link);
             edgeFound = true;
@@ -172,10 +172,10 @@ export const useNLMachineLearning = (props: {
    * after a community detection algorithm, where the cluster of these nodes could have been changed.
    */
   const resetClusterOfNodes = (type: number): void => {
-    props.graph.nodes.forEach((node: NodeType) => {
-      const numberOfClusters = props.numberOfMlClusters;
+    Object.keys(props.graph.nodes).forEach((key) => {
+      const node = props.graph.nodes[key];
       if (node.cluster == type) {
-        node.cluster = numberOfClusters;
+        node.cluster = props.numberOfMlClusters;
       }
       if (node.type == type) {
         node.cluster = node.type;
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx
index b9bfe5a06084e73f66b7a0241e5fe023a983ab7c..90919a26e89ab3f610a5a02111bf264aa2f853fb 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx
@@ -1,4 +1,4 @@
-import { GraphType, LinkType, NodeType } from '../types';
+import { GraphType, GraphTypeD3, LinkType, LinkTypeD3, NodeType, NodeTypeD3 } from '../types';
 import { dataColors, visualizationColors } from 'config';
 import { useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
 import {
@@ -19,23 +19,22 @@ import { NLPopup } from './NLPopup';
 import { hslStringToHex, nodeColor, nodeColorHex } from './utils';
 import { CytoscapeLayout, GraphologyLayout, LayoutFactory, Layouts } from '../../../../graph-layout';
 import { MultiGraph } from 'graphology';
-import { VisualizationSettingsType } from '../../../common';
 import { Viewport } from 'pixi-viewport';
 import { NodelinkVisProps } from '../nodelinkvis';
 import { Tooltip, TooltipContent, TooltipTrigger } from '@graphpolaris/shared/lib/components/tooltip';
 import { MovedEvent } from 'pixi-viewport/dist/types';
-
+import { ConstructionOutlined } from '@mui/icons-material';
 import { CardToolTipVis, CardToolTipVisProps } from '@graphpolaris/shared/lib/components/CardToolTipVis';
 
 type Props = {
-  onClick: (event?: { node: NodeType; pos: IPointData }) => void;
+  onClick: (event?: { node: NodeTypeD3; pos: IPointData }) => void;
   // onHover: (data: { node: NodeType; pos: IPointData }) => void;
   // onUnHover: (data: { node: NodeType; pos: IPointData }) => void;
   highlightNodes: NodeType[];
   configuration: NodelinkVisProps;
   currentShortestPathEdges?: LinkType[];
   highlightedLinks?: LinkType[];
-  graph?: GraphType;
+  graph: GraphType;
   layoutAlgorithm: string;
   showPopupsOnHover: boolean;
 };
@@ -48,13 +47,13 @@ type LayoutState = 'reset' | 'running' | 'paused';
 
 export const NLPixi = (props: Props) => {
   const [quickPopup, setQuickPopup] = useState<{ node: NodeType; pos: IPointData } | undefined>();
-  const [popups, setPopups] = useState<{ node: NodeType; pos: IPointData }[]>([]);
+  const [popups, setPopups] = useState<{ node: NodeTypeD3; pos: IPointData }[]>([]);
   const [assetsLoaded, setAssetsLoaded] = useState(false);
 
   const app = useMemo(
     () =>
       new Application({
-        background: 0xffffff,
+        backgroundAlpha: 0,
         antialias: true,
         autoDensity: true,
         eventMode: 'auto',
@@ -74,6 +73,7 @@ export const NLPixi = (props: Props) => {
   const isSetup = useRef(false);
   const ml = useML();
   const searchResults = useSearchResultData();
+  const graph = useRef<GraphTypeD3>({ nodes: [], links: [] });
 
   const layoutAlgorithm = useRef<CytoscapeLayout | GraphologyLayout>(new LayoutFactory().createLayout(Layouts.DAGRE));
 
@@ -128,10 +128,14 @@ export const NLPixi = (props: Props) => {
 
   useImperativeHandle(imperative, () => ({
     onMouseDown(event: FederatedPointerEvent) {
+      if (props.configuration.showPopUpOnHover) return;
+
       (event as any).mouseDownTimeStamp = event.timeStamp;
     },
 
     onMouseUpNode(event: FederatedPointerEvent) {
+      if (props.configuration.showPopUpOnHover) return;
+
       // If its a short click (not a drag) on the stage but not on a node: clear the selection and remove all popups.
       const holdDownTime = event.timeStamp - (event as any).mouseDownTimeStamp;
       if (holdDownTime > mouseClickThreshold) {
@@ -139,7 +143,7 @@ export const NLPixi = (props: Props) => {
       }
 
       const sprite = event.target as Sprite;
-      const node = (sprite as any).node as NodeType;
+      const node = (sprite as any).node as NodeTypeD3;
 
       if (event.shiftKey) {
         setPopups([...popups, { node: node, pos: toGlobal(node) }]);
@@ -150,6 +154,7 @@ export const NLPixi = (props: Props) => {
           sprite.texture = Assets.get(textureId(false));
         }
       }
+
       sprite.texture = Assets.get(textureId(true));
 
       props.onClick({ node: node, pos: toGlobal(node) });
@@ -158,6 +163,8 @@ export const NLPixi = (props: Props) => {
     },
 
     onMouseUpStage(event: FederatedPointerEvent) {
+      if (props.configuration.showPopUpOnHover) return;
+
       // If its a short click (not a drag) on the stage but not on a node: clear the selection and remove all popups.
       const holdDownTime = event.timeStamp - (event as any).mouseDownTimeStamp;
       if (holdDownTime < mouseClickThreshold) {
@@ -171,8 +178,10 @@ export const NLPixi = (props: Props) => {
     },
 
     onHover(event: FederatedPointerEvent) {
+      if (!props.configuration.showPopUpOnHover) return;
+
       const sprite = event.target as Sprite;
-      const node = (sprite as any).node as NodeType;
+      const node = (sprite as any).node as NodeTypeD3;
       if (
         mouseInCanvas.current &&
         viewport?.current &&
@@ -180,13 +189,17 @@ export const NLPixi = (props: Props) => {
         node &&
         popups.filter((p) => p.node._id === node._id).length === 0
       ) {
-        setQuickPopup({ node, pos: toGlobal(node) });
+        setQuickPopup({ node: props.graph.nodes[node._id], pos: toGlobal(node) });
       }
     },
     onUnHover() {
+      if (!props.configuration.showPopUpOnHover) return;
+
       setQuickPopup(undefined);
     },
     onMoved(event: MovedEvent) {
+      if (props.configuration.showPopUpOnHover) return;
+
       for (const popup of popups) {
         if (popup.node.x == null || popup.node.y == null) continue;
         popup.pos.x = event.viewport.transform.position.x + popup.node.x * event.viewport.scale.x;
@@ -224,7 +237,7 @@ export const NLPixi = (props: Props) => {
     }
   }, [ref]);
 
-  function toGlobal(node: NodeType): IPointData {
+  function toGlobal(node: NodeTypeD3): IPointData {
     if (viewport?.current) {
       // const rect = ref.current?.getBoundingClientRect();
       const rect = { x: 0, y: 0 };
@@ -234,18 +247,19 @@ export const NLPixi = (props: Props) => {
     } else return { x: 0, y: 0 };
   }
 
-  const updateNode = (node: NodeType) => {
+  const updateNode = (node: NodeTypeD3) => {
     const gfx = nodeMap.current.get(node._id);
     if (!gfx) return;
 
     // Update texture when selected
-    const texture = Assets.get(textureId(node.selected));
+    const nodeMeta = props.graph.nodes[node._id];
+    const texture = Assets.get(textureId(nodeMeta.selected));
     gfx.texture = texture;
     // Cluster colors
-    if (node?.cluster) {
-      gfx.tint = node.cluster >= 0 ? nodeColor(node.cluster) : 0x000000;
+    if (nodeMeta?.cluster) {
+      gfx.tint = nodeMeta.cluster >= 0 ? nodeColor(nodeMeta.cluster) : 0x000000;
     } else {
-      gfx.tint = nodeColor(node.type);
+      gfx.tint = nodeColor(nodeMeta.type);
     }
 
     gfx.position.set(node.x, node.y);
@@ -266,7 +280,9 @@ export const NLPixi = (props: Props) => {
     // }
   };
 
-  const createNode = (node: NodeType, selected?: boolean) => {
+  const createNode = (node: NodeTypeD3, selected?: boolean) => {
+    const nodeMeta = props.graph.nodes[node._id];
+
     // check if node is already drawn, and if so, delete it
     if (node && node?._id && nodeMap.current.has(node._id)) {
       nodeMap.current.delete(node._id);
@@ -278,8 +294,8 @@ export const NLPixi = (props: Props) => {
     const texture = Assets.get(textureId());
     sprite = new Sprite(texture);
 
-    sprite.tint = nodeColor(node.type);
-    const scale = (Math.max(node.radius || 5, 5) / 70) * 2;
+    sprite.tint = nodeColor(nodeMeta.type);
+    const scale = (Math.max(nodeMeta.radius || 5, 5) / 70) * 2;
     sprite.scale.set(scale, scale);
     sprite.anchor.set(0.5, 0.5);
 
@@ -291,7 +307,6 @@ export const NLPixi = (props: Props) => {
 
     nodeMap.current.set(node._id, sprite);
     nodeLayer.addChild(sprite);
-    node.selected = selected;
 
     updateNode(node);
     (sprite as any).node = node;
@@ -307,30 +322,30 @@ export const NLPixi = (props: Props) => {
   //   });
   // };
 
-  const updateLink = (link: LinkType) => {
+  const updateLink = (link: LinkTypeD3) => {
     if (!props.graph || nodeMap.current.size === 0) return;
+    const linkMeta = props.graph.links[link._id];
 
     const _source = link.source;
     const _target = link.target;
 
     if (!_source || !_target) {
-      console.log('source or target not found', _source, _target);
       return;
     }
 
     let sourceId = '';
     let targetId = '';
-    let source: NodeType | undefined;
-    let target: NodeType | undefined;
+    let source: NodeTypeD3 | undefined;
+    let target: NodeTypeD3 | undefined;
 
     if (typeof _source === 'string') {
       sourceId = link.source as string;
       targetId = link.target as string;
-      source = nodeMap.current.get(sourceId) as NodeType | undefined;
-      target = nodeMap.current.get(targetId) as NodeType | undefined;
+      source = nodeMap.current.get(sourceId) as NodeTypeD3 | undefined;
+      target = nodeMap.current.get(targetId) as NodeTypeD3 | undefined;
     } else {
-      source = link.source as NodeType;
-      target = link.target as NodeType;
+      source = link.source as NodeTypeD3;
+      target = link.target as NodeTypeD3;
       sourceId = source._id;
       targetId = target._id;
     }
@@ -343,28 +358,28 @@ export const NLPixi = (props: Props) => {
       // let color = link.color || 0x000000;
       let color = config.LINE_COLOR_DEFAULT;
       let style = config.LINE_WIDTH_DEFAULT;
-      let alpha = link.alpha || 1;
-      if (link.mlEdge) {
+      let alpha = linkMeta.alpha || 1;
+      if (linkMeta.mlEdge) {
         color = config.LINE_COLOR_ML;
-        if (link.value > ml.communityDetection.jaccard_threshold) {
-          style = link.value * 1.8;
+        if (linkMeta.value > ml.communityDetection.jaccard_threshold) {
+          style = linkMeta.value * 1.8;
         } else {
           style = 0;
           alpha = 0.2;
         }
-      } else if (props.highlightedLinks && props.highlightedLinks.includes(link)) {
-        if (link.mlEdge && ml.communityDetection.jaccard_threshold) {
-          if (link.value > ml.communityDetection.jaccard_threshold) {
+      } else if (props.highlightedLinks && props.highlightedLinks.includes(linkMeta)) {
+        if (linkMeta.mlEdge && ml.communityDetection.jaccard_threshold) {
+          if (linkMeta.value > ml.communityDetection.jaccard_threshold) {
             color = dataColors.magenta[50];
             // 0xaa00ff;
-            style = link.value * 1.8;
+            style = linkMeta.value * 1.8;
           }
         } else {
           color = dataColors.red[70];
           // color = 0xff0000;
           style = 1.0;
         }
-      } else if (props.currentShortestPathEdges && props.currentShortestPathEdges.includes(link)) {
+      } else if (props.currentShortestPathEdges && props.currentShortestPathEdges.includes(linkMeta)) {
         color = dataColors.green[50];
         // color = 0x00ff00;
         style = 3.0;
@@ -373,7 +388,7 @@ export const NLPixi = (props: Props) => {
       // Conditional alpha for search results
       if (searchResults.nodes.length > 0 || searchResults.edges.length > 0) {
         // FIXME: searchResults.edges should be a hashmap to improve performance.
-        const isLinkInSearchResults = searchResults.edges.some((resultEdge) => resultEdge.id === link.id);
+        const isLinkInSearchResults = searchResults.edges.some((resultEdge) => resultEdge.id === link._id);
         alpha = isLinkInSearchResults ? 1 : 0.05;
       }
 
@@ -413,11 +428,11 @@ export const NLPixi = (props: Props) => {
       if (isSetup.current === false) setup();
       else update(false);
     }
-  }, [props.graph, config, assetsLoaded]);
+  }, [config, assetsLoaded]);
 
   useEffect(() => {
     if (props.graph) {
-      props.graph.nodes.forEach((node: NodeType) => {
+      graph.current.nodes.forEach((node) => {
         const gfx = nodeMap.current.get(node._id);
         if (!gfx) return;
         const isNodeInSearchResults = searchResults.nodes.some((resultNode) => resultNode.id === node._id);
@@ -438,7 +453,7 @@ export const NLPixi = (props: Props) => {
 
       const widthHalf = app.renderer.width / 2;
       const heightHalf = app.renderer.height / 2;
-      props.graph.nodes.forEach((node: NodeType, i) => {
+      graph.current.nodes.forEach((node, i) => {
         if (!layoutAlgorithm.current) return;
         const gfx = nodeMap.current.get(node._id);
         if (!gfx || node.x === undefined || node.y === undefined) return;
@@ -449,24 +464,19 @@ export const NLPixi = (props: Props) => {
           stopped += 1;
           return;
         }
-        try {
-          if (layoutAlgorithm.current.provider === 'Graphology') {
-            // this is a dirty hack to fix the graphology layout being out of bounds
-            node.x = position.x + widthHalf;
-            node.y = position.y + heightHalf;
-          } else {
-            node.x = position.x;
-            node.y = position.y;
-          }
-        } catch (e) {
-          // node.x and .y become read-only when some layout algorithms are finished
-          layoutState.current = 'paused';
+        if (layoutAlgorithm.current.provider === 'Graphology') {
+          // this is a dirty hack to fix the graphology layout being out of bounds
+          node.x = position.x + widthHalf;
+          node.y = position.y + heightHalf;
+        } else {
+          node.x = position.x;
+          node.y = position.y;
         }
 
         gfx.position.copyFrom(node as IPointData);
       });
 
-      if (stopped === props.graph.nodes.length) {
+      if (stopped === graph.current.nodes.length) {
         layoutStoppedCount.current = layoutStoppedCount.current + 1;
         if (layoutStoppedCount.current > 1000) {
           layoutState.current = 'paused';
@@ -482,7 +492,7 @@ export const NLPixi = (props: Props) => {
       // Draw the links
       linkGfx.clear();
       linkGfx.beginFill();
-      props.graph.links.forEach((link: any) => {
+      graph.current.links.forEach((link: any) => {
         updateLink(link);
       });
       linkGfx.endFill();
@@ -500,7 +510,7 @@ export const NLPixi = (props: Props) => {
       }
 
       nodeMap.current.forEach((gfx, id) => {
-        if (!props.graph?.nodes?.find((node) => node._id === id)) {
+        if (!graph.current.nodes.find((node) => node._id === id)) {
           nodeLayer.removeChild(gfx);
           gfx.destroy();
           nodeMap.current.delete(id);
@@ -509,17 +519,13 @@ export const NLPixi = (props: Props) => {
 
       linkGfx.clear();
 
-      props.graph.nodes.forEach((node: NodeType) => {
+      graph.current.nodes.forEach((node) => {
         if (!forceClear && nodeMap.current.has(node._id)) {
           const old = nodeMap.current.get(node._id);
 
-          try {
-            node.x = old?.x || node.x;
-            node.y = old?.y || node.y;
-            updateNode(node);
-          } catch (e) {
-            // node.x and .y become read-only when some layout algorithms are finished
-          }
+          node.x = old?.x || node.x;
+          node.y = old?.y || node.y;
+          updateNode(node);
         } else {
           createNode(node);
         }
@@ -557,6 +563,16 @@ export const NLPixi = (props: Props) => {
 
     if (!props.graph) throw Error('Graph is undefined');
 
+    //Setup d3 graph structure
+    graph.current = {
+      nodes: Object.values(props.graph.nodes).map((n) => ({ _id: n._id, x: n.defaultX, y: n.defaultY })),
+      links: Object.values(props.graph.links).map((l) => ({
+        _id: l.id,
+        source: l.source,
+        target: l.target,
+      })),
+    };
+
     const size = ref.current?.getBoundingClientRect();
     viewport.current = new Viewport({
       screenWidth: size?.width || 1000,
@@ -593,12 +609,12 @@ export const NLPixi = (props: Props) => {
     if (!layoutAlgorithm) throw Error('LayoutAlgorithm is undefined');
 
     const graphologyGraph = new MultiGraph();
-    props.graph?.nodes.forEach((node) => {
-      if (forceClear) graphologyGraph.addNode(node._id, { size: node.radius || 5 });
-      else graphologyGraph.addNode(node._id, { size: node.radius || 5, x: node.x || 0, y: node.y || 0 });
+    graph.current.nodes.forEach((node) => {
+      if (forceClear) graphologyGraph.addNode(node._id, { size: props.graph.nodes[node._id].radius || 5 });
+      else graphologyGraph.addNode(node._id, { size: props.graph.nodes[node._id].radius || 5, x: node.x || 0, y: node.y || 0 });
     });
 
-    props.graph?.links.forEach((link) => {
+    graph.current.links.forEach((link) => {
       graphologyGraph.addEdge(link.source, link.target);
     });
     const boundingBox = { x1: 0, x2: app.renderer.screen.width, y1: 0, y2: app.renderer.screen.height };
@@ -612,21 +628,36 @@ export const NLPixi = (props: Props) => {
 
   return (
     <>
-      {popups.map((popup, index) => (
+      {popups.map((popup) => (
         <Tooltip key={popup.node._id} open={true} boundaryElement={ref} showArrow={true}>
           <TooltipTrigger x={popup.pos.x} y={popup.pos.y} />
           <TooltipContent>
             <div>
               <CardToolTipVis
                 type="popupvis"
-                name={popup.node.label}
-                colorHeader={nodeColorHex(popup.node.type)}
-                data={popup.node.attributes}
+                name={props.graph.nodes[popup.node._id].label}
+                colorHeader={nodeColorHex(props.graph.nodes[popup.node._id].type)}
+                data={props.graph.nodes[popup.node._id].attributes}
               />
             </div>
           </TooltipContent>
         </Tooltip>
       ))}
+      {quickPopup != null && (
+        <Tooltip key={quickPopup.node._id} open={true} boundaryElement={ref} showArrow={true}>
+          <TooltipTrigger x={quickPopup.pos.x} y={quickPopup.pos.y} />
+          <TooltipContent>
+            <div>
+              <CardToolTipVis
+                type="popupvis"
+                name={props.graph.nodes[quickPopup.node._id].label}
+                colorHeader={nodeColorHex(props.graph.nodes[quickPopup.node._id].type)}
+                data={props.graph.nodes[quickPopup.node._id].attributes}
+              />
+            </div>
+          </TooltipContent>
+        </Tooltip>
+      )}
       <div
         className="h-full w-full overflow-hidden"
         ref={ref}
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/components/query2NL.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/components/query2NL.tsx
index 990719dc6febaa81440ac6f1c8d1aa8fd71c535b..952d6bc4eb2a9ee83f68aa19849474238eddcf39 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/components/query2NL.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/components/query2NL.tsx
@@ -142,7 +142,11 @@ type OptionsI = {
  * @returns {GraphType} A node-link graph containing the nodes and links for the diagram.
  */
 export function parseQueryResult(queryResult: GraphQueryResult, ml: ML, options: OptionsI = {}): GraphType {
-  const nodes: NodeType[] = [];
+  let ret: GraphType = {
+    nodes: {},
+    links: {},
+  };
+
   const typeDict: { [key: string]: number } = {};
   // Counter for the types
   let counter = 1;
@@ -184,8 +188,8 @@ export function parseQueryResult(queryResult: GraphQueryResult, ml: ML, options:
       type: typeNumber,
       displayInfo: preferredText,
       radius: radius,
-      x: (options.defaultX || 0) + Math.random() * radius * 20 - radius * 10,
-      y: (options.defaultY || 0) + Math.random() * radius * 20 - radius * 10,
+      defaultX: (options.defaultX || 0) + Math.random() * radius * 20 - radius * 10,
+      defaultY: (options.defaultY || 0) + Math.random() * radius * 20 - radius * 10,
     };
 
     // let mlExtra = {};
@@ -209,13 +213,13 @@ export function parseQueryResult(queryResult: GraphQueryResult, ml: ML, options:
 
     // Add mlExtra to the node if necessary
     // data = { ...data, ...mlExtra };
-    nodes.push(data);
+    ret.nodes[data._id] = data;
   }
 
   // Filter unique edges and transform to LinkTypes
   // List for all links
   let links: LinkType[] = [];
-  let allNodeIds = new Set(nodes.map((n) => n._id));
+  let allNodeIds = new Set(Object.keys(ret.nodes));
 
   // Parse ml edges
   //   if (ml != undefined) {
@@ -239,14 +243,14 @@ export function parseQueryResult(queryResult: GraphQueryResult, ml: ML, options:
   for (let i = 0; i < uniqueEdges.length; i++) {
     if (allNodeIds.has(uniqueEdges[i].from) && allNodeIds.has(uniqueEdges[i].to)) {
       const toAdd: LinkType = {
-        id: uniqueEdges[i].from + ':' + uniqueEdges[i].to,
+        id: uniqueEdges[i].from + ':' + uniqueEdges[i].to, // TODO: this only supports one link between two nodes
         source: uniqueEdges[i].from,
         target: uniqueEdges[i].to,
         value: uniqueEdges[i].count,
         mlEdge: false,
         color: 0x000000,
       };
-      links.push(toAdd);
+      ret.links[toAdd.id] = toAdd;
     }
   }
 
@@ -266,13 +270,13 @@ export function parseQueryResult(queryResult: GraphQueryResult, ml: ML, options:
   }
 
   // Graph to be returned
-  let toBeReturned: GraphType = {
-    nodes: nodes,
-    links: links,
-    // linkPrediction: linkPredictionInResult,
-    // shortestPath: shortestPathInResult,
-    // communityDetection: communityDetectionInResult,
-  };
+  // let toBeReturned: GraphType = {
+  //   nodes: nodes,
+  //   links: links,
+  // linkPrediction: linkPredictionInResult,
+  // shortestPath: shortestPathInResult,
+  // communityDetection: communityDetectionInResult,
+  // };
 
   // If query with community detection; add number of clusters to the graph
   // const numberOfClusters = {
@@ -283,5 +287,5 @@ export function parseQueryResult(queryResult: GraphQueryResult, ml: ML, options:
   // }
 
   // return toBeReturned;
-  return processML(ml, toBeReturned);
+  return processML(ml, ret);
 }
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/components/utils.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/components/utils.tsx
index 73012f7de90bd815acdcd9a923e222821bcf8dc5..6e336b56f23cd36053a2b820f49b7a3cd21d4a11 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/components/utils.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/components/utils.tsx
@@ -68,11 +68,12 @@ export function hslStringToHex(hsl: string) {
  */
 export const getRelatedLinks = (graph: GraphType, nodes: NodeType[], jaccardThreshold: number): LinkType[] => {
   const relatedLinks: LinkType[] = [];
-  graph.links.forEach((link: LinkType) => {
+  Object.keys(graph.links).forEach((id) => {
+    const link = graph.links[id];
     const { source, target } = link;
     if (isLinkVisible(link, jaccardThreshold)) {
       nodes.forEach((node: NodeType) => {
-        if (source == node || target == node || source == node._id || target == node._id) {
+        if (source == node._id || target == node._id || source == node._id || target == node._id) {
           relatedLinks.push(link);
         }
       });
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
index 70c7867ba36adf9dbfe162a15f597dbce985a20d..4daa884911470b09db5daa4058e226ddb7267d54 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
@@ -1,5 +1,5 @@
 import React, { useEffect, useRef, useState } from 'react';
-import { GraphType, LinkType, NodeType } from './types';
+import { GraphType, LinkType, NodeType, NodeTypeD3 } from './types';
 import { NLPixi } from './components/NLPixi';
 import { parseQueryResult } from './components/query2NL';
 import { useImmer } from 'use-immer';
@@ -66,7 +66,7 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch, settings, handleSel
     }
   }, [data, ml]);
 
-  const onClickedNode = (event?: { node: NodeType; pos: IPointData }, ml?: ML) => {
+  const onClickedNode = (event?: { node: NodeTypeD3; pos: IPointData }, ml?: ML) => {
     if (graph) {
       if (!event?.node) {
         handleSelect();
@@ -74,11 +74,12 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch, settings, handleSel
       }
 
       const node = event.node;
-      handleSelect({ nodes: [node as Node] });
+      const nodeMeta = graph.nodes[node._id];
+      handleSelect({ nodes: [nodeMeta as Node] });
 
       if (ml && ml.shortestPath.enabled) {
         setGraph((draft) => {
-          let _node = draft?.nodes.find((n) => n._id === node._id);
+          let _node = draft?.nodes[node._id];
           if (!_node) return draft;
 
           if (!ml.shortestPath.srcNode) {
@@ -105,6 +106,7 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch, settings, handleSel
     }
   };
 
+  if (!graph) return null;
   return (
     <NLPixi
       graph={graph}
@@ -177,7 +179,7 @@ const NodelinkSettings = ({ settings, graphMetadata, updateSettings }: Visualiza
               type="dropdown"
               label="Shape"
               value={settings.shapes.shape}
-              options={[{circle: 'Circle'}, {rectangle: 'Square'}]}
+              options={[{ circle: 'Circle' }, { rectangle: 'Square' }]}
               onChange={(val) => updateSettings({ shapes: { ...settings.shapes, shape: val as any } })}
             />
           ) : (
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/types.ts b/libs/shared/lib/vis/visualizations/nodelinkvis/types.ts
index 7374b774b60577320b3a832c1fe096b94fd8c287..321f20198e309108b450dc0d352eb15ef9216950 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/types.ts
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/types.ts
@@ -9,16 +9,21 @@ import { Node } from '@graphpolaris/shared/lib/data-access/store/graphQueryResul
 
 /** Types for the nodes and links in the node-link diagram. */
 export type GraphType = {
-  nodes: NodeType[];
-  links: LinkType[];
+  nodes: Record<string, NodeType>; // _id -> node
+  links: Record<string, LinkType>; // _id -> link
   // linkPrediction?: boolean;
   // shortestPath?: boolean;
   // communityDetection?: boolean;
   // numberOfMlClusters?: number;
 };
 
+export type GraphTypeD3 = {
+  nodes: NodeTypeD3[];
+  links: LinkTypeD3[];
+};
+
 /** The interface for a node in the node-link diagram */
-export interface NodeType extends d3.SimulationNodeDatum, Node {
+export interface NodeType extends Node {
   _id: string;
 
   // Number to determine the color of the node
@@ -41,28 +46,14 @@ export interface NodeType extends d3.SimulationNodeDatum, Node {
 
   // The text that will be shown on top of the node if selected.
   displayInfo?: string;
-
-  // Node’s current x-position.
-  x?: number;
-
-  // Node’s current y-position.
-  y?: number;
-
-  // Node’s current x-velocity
-  vx?: number;
-
-  // Node’s current y-velocity
-  vy?: number;
-
-  // Node’s fixed x-position (if position was fixed)
-  fx?: number | null;
-
-  // Node’s fixed y-position (if position was fixed)
-  fy?: number | null;
+  defaultX?: number;
+  defaultY?: number;
 }
 
+export type NodeTypeD3 = d3.SimulationNodeDatum & { _id: string };
+
 /** The interface for a link in the node-link diagram */
-export interface LinkType extends d3.SimulationLinkDatum<NodeType> {
+export interface LinkType {
   // The thickness of a line
   id: string;
   value: number;
@@ -70,14 +61,18 @@ export interface LinkType extends d3.SimulationLinkDatum<NodeType> {
   mlEdge: boolean;
   color: number;
   alpha?: number;
+  source: string;
+  target: string;
 }
 
+export type LinkTypeD3 = d3.SimulationLinkDatum<NodeTypeD3> & { _id: string };
+
 /**collectionNode holds 1 entry per node kind (so for example a MockNode with name "parties" and all associated attributes,) */
 export type TypeNode = {
   name: string; //Collection name
   attributes: string[]; //attributes. This includes all attributes found in the collection
   type: number | undefined; //number that represents collection of node, for colorscheme
-  visualisations: Visualization[]; //The way to visualize attributes of this Node kind
+  visualizations: Visualization[]; //The way to visualize attributes of this Node kind
 };
 
 export type CommunityDetectionNode = {