Traits and Machine UI
MBD2 21.1.1A trait is a configurable machine component. Keep three IO systems separate: recipe-handler IO, sided block-capability IO, and automatic world IO.

Configure a trait
| Setting | Purpose |
|---|---|
| Trait name | Stable lookup name for KubeJS and generated ui:<name> IDs |
| Recipe handler IO | Whether recipe logic may consume from or produce into the trait |
| Recipe logics | Which of the machine's recipe logics may use the trait; empty for all |
| Distinct | Whether capability content must be handled without combining across handlers |
| Slot names | Optional routing names referenced by recipe slotName |
| Capability IO | Which world-facing sides allow insertion/extraction, relative to machine front |
| GUI IO | Which actions the machine UI permits |
| Auto IO | Periodic transfer to/from adjacent block capabilities |
| Filter/capacity/rate | Trait-specific storage constraints |
| Keep data on drop | Whether the dropped machine item carries the trait's data, see below |
Core traits
| Trait type | Runtime storage | Recipe handlers | World capability |
|---|---|---|---|
item_slot | Item stack transfer | item, item_durability | Sided item handler |
fluid_tank | Fluid storage list | fluid | Sided fluid handler |
forge_energy_storage | Copiable energy storage | forge_energy | Capabilities.EnergyStorage.BLOCK |
entity_handler | Entity interaction configuration | entity | Behaviour-oriented; not normal inventory storage |
Optional traits appear only with their dependency: chemical_tank, mek_heat_container, pneumatic_pressure_air_handler, pneumatic_heat_exchanger, aura_handler, ars_source_storage, ars_nearby_source, ae2_me_interface, ae2_me_pattern_provider, astral_lumen_storage, astral_starlight_receiver, astral_researcher. See Integrations.
Item slots past a stack
Since after 21.1.2An item_slot trait's Slot Limit is how many items one slot holds. Up to 21.1.2 a slot never held more than the item's own max stack size, usually 64. Turn on Ignore item stack limit and it holds up to the slot limit instead, as many as 2,147,483,647.
- Items that do not stack, such as tools, still go one per slot.
- The slot shows a count of 1000 or more shortened; its tooltip has the full count.
- A click takes at most one stack out. Hoppers, pipes and auto IO move items as usual, and recipes consume and produce any amount.
- A broken machine drops the items as normal stacks. Turn Drop items off and they are lost instead, or turn on Keep data on drop to keep them in the machine item.
slot_limitandignore_item_stack_limitare runtime values, so one placed machine can change either.
Keep data on drop
Since after 21.1.2Every trait has Keep data on drop. Turned on, breaking the machine writes the trait's data — an item slot's contents, a tank's fluid, an energy store's charge, the trait's runtime values — into the dropped machine item, and placing that item gives it all back. The trait then drops nothing of its own, unless the machine drops no item at all. A trait still as it was when the machine was new adds nothing to the item, so machines broken empty still stack.
Every setting here is overridable per machine
Trait settings are also runtime values: recipe handler IO, distinct, slot names, capability IO, auto IO, capacities and filters can all be overridden on one placed machine by a blueprint or a script, without touching the definition.
Generate and bind UI

Trait definitions implementing IUIProviderTrait create templates using IDs based on ui:<trait-name>. SLOT layouts flow into input/output columns; BAR layouts flow below them. The UI generator can also add recipe progress, fuel progress, recipe-viewer lookup, and player inventory; a machine with several recipe logics gets a progress and a fuel bar for each.
Generate after trait names and counts are stable. If you rename a trait, verify all generated widget IDs, recipe slotName/uiName, and scripts.
At runtime, initTraitUI binds the actual trait to matching widgets. Storage remains server-authoritative; controls should send actions or use data bindings rather than directly trusting client-side values.
Cross-part UI
A multiblock controller's UI can bind a widget to a trait that lives on one of its parts, and a part's UI can bind to a trait on its controller. Give the element a prefixed ID in the editor:
| On | ID form | Binds to |
|---|---|---|
| A controller's UI | part:<traitName>@ui:<widgetId> | That trait on any formed part |
| A part's UI | controller:<traitName>@ui:<widgetId> | That trait on any controller — needs part settings enabled |
<widgetId> is the generated widget ID with its ui: prefix dropped, so a part trait named input_items whose first slot is ui:input_items_0 is reached as part:input_items@ui:input_items_0.
At bind time MBD2 finds the trait, rewrites the element's ID back to ui:input_items_0 and runs that trait's initTraitUI. If no part or controller has a trait with that name, or the trait provides no UI, the element is left alone.
For resources rather than widgets, use capability proxying — see Multiblocks.
Adding UI from a blueprint
A blueprint can hook the Build UI event and append to the screen the editor authored. The Auto IO panel built-in does exactly that, and it is the pattern for any UI a machine should get without editing its UI tree.