App Component Tree¶
Audience: Users who want to know how components can be composed with each other.
Level: Basic
What is an Application Component Tree?¶
Components can be nested to form component trees where the LightningFlows are its branches and LightningWorks are its leaves.
This design enables users to organize and maintain their code with more ease, but more importantly, this helps creating an ecosystem with re-usable components.
Here’s a basic application with four flows and two works (associated tree structure):

import lightning as L
from lightning.app.testing import EmptyFlow, EmptyWork
class FlowB(L.LightningFlow):
def __init__(self):
super().__init__()
self.flow_d = EmptyFlow()
self.work_b = EmptyWork()
def run(self):
...
class FlowA(L.LightningFlow):
def __init__(self):
super().__init__()
self.flow_b = FlowB()
self.flow_c = EmptyFlow()
self.work_a = EmptyWork()
def run(self):
...
app = L.LightningApp(FlowA())
A Lightning app runs all flows into a single process. Its flows coordinate the execution of the works each running in their own independent processes.
How do I define my application component tree?¶
In order to define your application component tree, you need create a tree of components and attach them to your root flow.
You can attach your components in the __init__ method of a flow.
import lightning as L
class RootFlow(L.LightningFlow):
def __init__(self):
super().__init__()
# The `Work` component is attached here.
self.work = Work()
# The `NestedFlow` component is attached here.
self.nested_flow = NestedFlow()
Once done, simply add the root flow to a Lightning app as follows:
app = L.LightningApp(RootFlow())
Is my application component tree static?¶
No, Lightning supports dynamic flows and works.
You can simply attach your components in the run method of a flow using the Python functions hasattr, setattr, and getattr.
class RootFlow(L.LightningFlow):
def run(self):
if not hasattr(self, "work"):
# The `Work` component is attached here.
setattr(self, "work", Work())
# Run the `Work` component.
getattr(self, "work").run()
if not hasattr(self, "nested_flow"):
# The `NestedFlow` component is attached here.
setattr(self, "nested_flow", NestedFlow())
# Run the `NestedFlow` component.
getattr(self, "wonested_flowrk").run()
But it is usually more readable to use Lightning built-in Dict
or List
as follows:
from lightning.app.structures import Dict
class RootFlow(L.LightningFlow):
def __init__(self):
super().__init__()
self.dict = Dict()
def run(self):
if "work" not in self.dict:
# The `Work` component is attached here.
self.dict["work"] = Work()
self.dict["work"].run()
if "nested_flow" not in self.dict:
# The `NestedFlow` component is attached here.
self.dict["nested_flow"] = NestedFlow()
self.dict["nested_flow"].run()