I need help with library organization in a custom Dynamo package (tree structure).
This is a sample test package I built to check how Dynamo reads categories and node organization.
I’m currently working on UI-based nodes, and for maintainability I need to keep each node’s code in its own separate .cs file — but Dynamo isn’t grouping them correctly in the library.
My Current Setup
Package name: MyTest
Environment: Revit 2025 + Dynamo 3.3
Build target: .NET 8.0 (x64)
What I Expect
In Dynamo’s library I want a clean hierarchy like this:
MyTest
├─ Elements
│ ├─ Get Parameter (String)
│ └─ Set Parameter (String)
└─ Math
├─ Addition
└─ Multiplication
What I’m Actually Getting
Dynamo adds extra sub-categories based on my class names, resulting in this unwanted structure:
MyTest
├─ Elements
│ ├─ GetParameterNode
│ │ └─ GetParameter
│ └─ SetParameterNode
│ └─ SetParameter
└─ Math
├─ AdditionNode
│ └─ Addition
└─ MultiplicationNode
└─ Multiplication
How can I define my nodes so Dynamo does not create sub-folders based on class names
and the nodes appear directly under MyTest.Elements and MyTest.Math as intended —
while still keeping each node in a separate .cs file?
MyTest.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Platforms>x64</Platforms>
<UseWPF>false</UseWPF>
<AssemblyName>MyTest</AssemblyName>
<RootNamespace>MyTest</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Reference Include="DynamoServices">
<HintPath>..\..\..\..\..\Program Files\Autodesk\Revit 2025\AddIns\DynamoForRevit\DynamoServices.dll</HintPath>
</Reference>
<Reference Include="ProtoGeometry">
<HintPath>$(ProgramFiles)\Autodesk\Revit 2025\AddIns\DynamoForRevit\ProtoGeometry.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="DynamoCore">
<HintPath>$(ProgramFiles)\Autodesk\Revit 2025\AddIns\DynamoForRevit\DynamoCore.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="RevitServices">
<HintPath>$(ProgramFiles)\Autodesk\Revit 2025\AddIns\DynamoForRevit\Revit\RevitServices.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="RevitAPI">
<HintPath>$(ProgramFiles)\Autodesk\Revit 2025\RevitAPI.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="RevitNodes">
<HintPath>$(ProgramFiles)\Autodesk\Revit 2025\AddIns\DynamoForRevit\Revit\RevitNodes.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
</Project>
GetParameter.cs
using Dynamo.Graph.Nodes;
using RevitServices.Persistence;
using DB = Autodesk.Revit.DB;
using RevitElement = Revit.Elements.Element;
namespace MyTest.Elements
{
[NodeCategory("MyTest.Elements")]
public static class GetParameterNode
{
[NodeName("Get Parameter (String)")]
[NodeDescription("Returns the string value of a parameter (only for string parameters).")]
public static string GetParameter(RevitElement element, string parameterName)
{
if (element == null || string.IsNullOrWhiteSpace(parameterName)) return null;
var dbElem = element.InternalElement as DB.Element;
if (dbElem == null) return null;
var p = dbElem.LookupParameter(parameterName);
if (p == null || p.StorageType != DB.StorageType.String) return null;
return p.AsString();
}
}
}
SetParameter.cs
using System;
using Dynamo.Graph.Nodes;
using RevitServices.Persistence;
using DB = Autodesk.Revit.DB;
using RevitElement = Revit.Elements.Element;
namespace MyTest.Elements
{
[NodeCategory("MyTest.Elements")]
public static class SetParameterNode
{
[NodeName("Set Parameter (String)")]
[NodeDescription("Sets the string value of a parameter (only for string parameters). Returns the same element.")]
public static RevitElement SetParameter(RevitElement element, string parameterName, string value)
{
if (element == null || string.IsNullOrWhiteSpace(parameterName)) return null;
var doc = DocumentManager.Instance.CurrentDBDocument;
var dbElem = element.InternalElement as DB.Element;
if (dbElem == null) return element;
var p = dbElem.LookupParameter(parameterName);
if (p == null || p.StorageType != DB.StorageType.String) return element;
// Fully-qualified TransactionManager to avoid ambiguity
RevitServices.Transactions.TransactionManager.Instance.EnsureInTransaction(doc);
try
{
p.Set(value ?? string.Empty);
}
finally
{
RevitServices.Transactions.TransactionManager.Instance.TransactionTaskDone();
}
return element;
}
}
}
Addition.cs
using Dynamo.Graph.Nodes;
namespace MyTest.Math
{
[NodeCategory("MyTest.Math")]
public static class AdditionNode
{
[NodeName("Addition")]
[NodeDescription("Adds two numbers.")]
public static double Addition(double a, double b) => a + b;
}
}
Multiplication.cs
using Dynamo.Graph.Nodes;
namespace MyTest.Math
{
[NodeCategory("MyTest.Math")]
public static class MultiplicationNode
{
[NodeName("Multiplication")]
[NodeDescription("Multiplies two numbers.")]
public static double Multiplication(double a, double b) => a * b;
}
}

