Skip to main content

Create custom Python components

Custom components extend Langflow's functionality through Python classes that inherit from Component. This enables integration of new features, data manipulation, external services, and specialized tools.

In Langflow's node-based environment, each node is a "component" that performs discrete functions. Custom components are Python classes which define:

  • Inputs — Data or parameters your component requires.
  • Outputs — Data your component provides to downstream nodes.
  • Logic — How you process inputs to produce outputs.

The benefits of creating custom components include unlimited extensibility, reusability, automatic UI field generation based on inputs, and type-safe connections between nodes.

Create custom components for performing specialized tasks, calling APIs, or adding advanced logic.

Custom components in Langflow are built upon:

  • The Python class that inherits from Component.
  • Class-level attributes that identify and describe the component.
  • Input and output lists that determine data flow.
  • Internal variables for logging and advanced logic.

Class-level attributes

Define these attributes to control a custom component's appearance and behavior:


_10
class MyCsvReader(Component):
_10
display_name = "CSV Reader" # Shown in node header
_10
description = "Reads CSV files" # Tooltip text
_10
icon = "file-text" # Visual identifier
_10
name = "CSVReader" # Unique internal ID
_10
documentation = "http://docs.example.com/csv_reader" # Optional

  • display_name: A user-friendly label in the node header.
  • description: A brief summary shown in tooltips.
  • icon: A visual identifier from Langflow's icon library.
  • name: A unique internal identifier.
  • documentation: An optional link to external docs.

Structure of a custom component

A Langflow custom component goes beyond a simple class with inputs and outputs. It includes an internal structure with optional lifecycle steps, output generation, front-end interaction, and logic organization.

A basic component:

  • Inherits from langflow.custom.Component.
  • Declares metadata like display_name, description, icon, and more.
  • Defines inputs and outputs lists.
  • Implements methods matching output specifications.

A minimal custom component skeleton contains the following:


_14
from langflow.custom import Component
_14
from langflow.template import Output
_14
_14
class MyComponent(Component):
_14
display_name = "My Component"
_14
description = "A short summary."
_14
icon = "sparkles"
_14
name = "MyComponent"
_14
_14
inputs = []
_14
outputs = []
_14
_14
def some_output_method(self):
_14
return ...

Internal Lifecycle and Execution Flow

Langflow's engine manages:

  • Instantiation: A component is created and internal structures are initialized.
  • Assigning Inputs: Values from the UI or connections are assigned to component fields.
  • Validation and Setup: Optional hooks like _pre_run_setup.
  • Outputs Generation: run() or build_results() triggers output methods.

Optional Hooks:

  • initialize_data or _pre_run_setup can run setup logic before the component's main execution.
  • __call__, run(), or _run() can be overridden to customize how the component is called or to define custom execution logic.

Inputs and outputs

Custom component inputs are defined with properties like:

  • name, display_name
  • Optional: info, value, advanced, is_list, tool_mode, real_time_refresh

For example:

  • StrInput: simple text input.
  • DropdownInput: selectable options.
  • HandleInput: specialized connections.

Custom component Output properties define:

  • name, display_name, method
  • Optional: info

For more information, see Custom component inputs and outputs.

Associated Methods

Each output is linked to a method:

  • The output method name must match the method name.
  • The method typically returns objects like Message, Data, or DataFrame.
  • The method can use inputs with self.<input_name>.

For example:


_12
Output(
_12
display_name="File Contents",
_12
name="file_contents",
_12
method="read_file"
_12
)
_12
#...
_12
def read_file(self) -> Data:
_12
path = self.filename
_12
with open(path, "r") as f:
_12
content = f.read()
_12
self.status = f"Read {len(content)} chars from {path}"
_12
return Data(data={"content": content})

Components with multiple outputs

A component can define multiple outputs. Each output can have a different corresponding method. For example:


_10
outputs = [
_10
Output(display_name="Processed Data", name="processed_data", method="process_data"),
_10
Output(display_name="Debug Info", name="debug_info", method="provide_debug_info"),
_10
]

Common internal patterns

_pre_run_setup()

To initialize a custom component with counters set:


_10
def _pre_run_setup(self):
_10
if not hasattr(self, "_initialized"):
_10
self._initialized = True
_10
self.iteration = 0

Override run or _run

You can override async def _run(self): ... to define custom execution logic, although the default behavior from the base class usually covers most cases.

Store data in self.ctx

Use self.ctx as a shared storage for data or counters across the component's execution flow:


_10
def some_method(self):
_10
count = self.ctx.get("my_count", 0)
_10
self.ctx["my_count"] = count + 1

Directory structure requirements

By default, Langflow looks for custom components in the langflow/components directory.

If you're creating custom components in a different location using the LANGFLOW_COMPONENTS_PATH environment variable, components must be organized in a specific directory structure to be properly loaded and displayed in the UI:


_10
/your/custom/components/path/ # Base directory set by LANGFLOW_COMPONENTS_PATH
_10
└── category_name/ # Required category subfolder that determines menu name
_10
└── custom_component.py # Component file

Components must be placed inside category folders, not directly in the base directory. The category folder name determines where the component appears in the UI menu.

For example, to add a component to the Helpers menu, place it in a helpers subfolder:


_10
/app/custom_components/ # LANGFLOW_COMPONENTS_PATH
_10
└── helpers/ # Displayed within the "Helpers" menu
_10
└── custom_component.py # Your component

You can have multiple category folders to organize components into different menus:


_10
/app/custom_components/
_10
├── helpers/
_10
│ └── helper_component.py
_10
└── tools/
_10
└── tool_component.py

This folder structure is required for Langflow to properly discover and load your custom components. Components placed directly in the base directory will not be loaded.


_10
/app/custom_components/ # LANGFLOW_COMPONENTS_PATH
_10
└── custom_component.py # Won't be loaded - missing category folder!

Custom component inputs and outputs

Inputs and outputs define how data flows through the component, how it appears in the UI, and how connections to other components are validated.

Inputs

Inputs are defined in a class-level inputs list. When Langflow loads the component, it uses this list to render fields and handles in the UI. Users or other components provide values or connections to fill these inputs.

An input is usually an instance of a class from langflow.io (such as StrInput, DataInput, or MessageTextInput). The most common constructor parameters are:

  • name: The internal variable name, accessed via self.<name>.
  • display_name: The label shown to users in the UI.
  • info (optional): A tooltip or short description.
  • value (optional): The default value.
  • advanced (optional): If True, moves the field into the "Advanced" section.
  • required (optional): If True, forces the user to provide a value.
  • is_list (optional): If True, allows multiple values.
  • input_types (optional): Restricts allowed connection types (e.g., ["Data"], ["LanguageModel"]).

Here are the most commonly used input classes and their typical usage.

Text Inputs: For simple text entries.

  • StrInput creates a single-line text field.
  • MultilineInput creates a multi-line text area.

Numeric and Boolean Inputs: Ensures users can only enter valid numeric or boolean data.

  • BoolInput, IntInput, and FloatInput provide fields for boolean, integer, and float values, ensuring type consistency.

Dropdowns: For selecting from predefined options, useful for modes or levels.

  • DropdownInput

Secrets: A specialized input for sensitive data, ensuring input is hidden in the UI.

  • SecretStrInput for API keys and passwords.

Specialized Data Inputs: Ensures type-checking and color-coded connections in the UI.

  • DataInput expects a Data object (typically with .data and optional .text).
  • MessageInput expects a Message object, used in chat or agent-based flows.
  • MessageTextInput simplifies access to the .text field of a Message.

Handle-Based Inputs: Used to connect outputs of specific types, ensuring correct pipeline connections.

  • HandleInput

File Uploads: Allows users to upload files directly through the UI or receive file paths from other components.

  • FileInput

Lists: Set is_list=True to accept multiple values, ideal for batch or grouped operations.

This example defines three inputs: a text field (StrInput), a boolean toggle (BoolInput), and a dropdown selection (DropdownInput).


_10
from langflow.io import StrInput, BoolInput, DropdownInput
_10
_10
inputs = [
_10
StrInput(name="title", display_name="Title"),
_10
BoolInput(name="enabled", display_name="Enabled", value=True),
_10
DropdownInput(name="mode", display_name="Mode", options=["Fast", "Safe", "Experimental"], value="Safe")
_10
]

Outputs

Outputs are defined in a class-level outputs list. When Langflow renders a component, each output becomes a connector point in the UI. When you connect something to an output, Langflow automatically calls the corresponding method and passes the returned object to the next component.

An output is usually an instance of Output from langflow.io, with common parameters:

  • name: The internal variable name.
  • display_name: The label shown in the UI.
  • method: The name of the method called to produce the output.
  • info (optional): Help text shown on hover.

The method must exist in the class, and it is recommended to annotate its return type for better type checking. You can also set a self.status message inside the method to show progress or logs.

Common Return Types:

  • Message: Structured chat messages.
  • Data: Flexible object with .data and optional .text.
  • DataFrame: Pandas-based tables (langflow.schema.DataFrame).
  • Primitive types: str, int, bool (not recommended if you need type/color consistency).

In this example, the DataToDataFrame component defines its output using the outputs list. The df_out output is linked to the build_df method, so when connected in the UI, Langflow calls this method and passes its returned DataFrame to the next node. This demonstrates how each output maps to a method that generates the actual output data.


_37
from langflow.custom import Component
_37
from langflow.io import DataInput, Output
_37
from langflow.schema import Data, DataFrame
_37
_37
class DataToDataFrame(Component):
_37
display_name = "Data to DataFrame"
_37
description = "Convert multiple Data objects into a DataFrame"
_37
icon = "table"
_37
name = "DataToDataFrame"
_37
_37
inputs = [
_37
DataInput(
_37
name="items",
_37
display_name="Data Items",
_37
info="List of Data objects to convert",
_37
is_list=True
_37
)
_37
]
_37
_37
outputs = [
_37
Output(
_37
name="df_out",
_37
display_name="DataFrame Output",
_37
method="build_df"
_37
)
_37
]
_37
_37
def build_df(self) -> DataFrame:
_37
rows = []
_37
for item in self.items:
_37
row_dict = item.data.copy() if item.data else {}
_37
row_dict["text"] = item.get_text() or ""
_37
rows.append(row_dict)
_37
_37
df = DataFrame(rows)
_37
self.status = f"Built DataFrame with {len(rows)} rows."
_37
return df

Tool mode

You can configure a Custom Component to work as a Tool by setting the parameter tool_mode=True. This allows the component to be used in Langflow's Tool Mode workflows, such as by Agent components.

Langflow currently supports the following input types for Tool Mode:

  • DataInput
  • DataFrameInput
  • PromptInput
  • MessageTextInput
  • MultilineInput
  • DropdownInput

_10
inputs = [
_10
MessageTextInput(
_10
name="message",
_10
display_name="Mensage",
_10
info="Enter the message that will be processed directly by the tool",
_10
tool_mode=True,
_10
),
_10
]

Typed annotations

In Langflow, typed annotations allow Langflow to visually guide users and maintain flow consistency.

Typed annotations provide:

  • Color-coding: Outputs like -> Data or -> Message get distinct colors.
  • Validation: Langflow blocks incompatible connections automatically.
  • Readability: Developers can quickly understand data flow.
  • Development tools: Better code suggestions and error checking in your code editor.

Common Return Types

Message

For chat-style outputs.


_10
def produce_message(self) -> Message:
_10
return Message(text="Hello! from typed method!", sender="System")

In the UI, connects only to Message-compatible inputs.

Data

For structured data like dicts or partial texts.


_10
def get_processed_data(self) -> Data:
_10
processed = {"key1": "value1", "key2": 123}
_10
return Data(data=processed)

In the UI, connects only with DataInput.

DataFrame

For tabular data


_10
def build_df(self) -> DataFrame:
_10
pdf = pd.DataFrame({"A": [1, 2], "B": [3, 4]})
_10
return DataFrame(pdf)

In the UI, connects only to DataFrameInput.

Primitive Types (str, int, bool)

Returning primitives is allowed but wrapping in Data or Message is recommended for better UI consistency.


_10
def compute_sum(self) -> int:
_10
return sum(self.numbers)

Tips for typed annotations

When using typed annotations, consider the following best practices:

  • Always Annotate Outputs: Specify return types like -> Data, -> Message, or -> DataFrame to enable proper UI color-coding and validation.
  • Wrap Raw Data: Use Data, Message, or DataFrame wrappers instead of returning plain structures.
  • Use Primitives Carefully: Direct str or int returns are fine for simple flows, but wrapping improves flexibility.
  • Annotate Helpers Too: Even if internal, typing improves maintainability and clarity.
  • Handle Edge Cases: Prefer returning structured Data with error fields when needed.
  • Stay Consistent: Use the same types across your components to make flows predictable and easier to build.

Enable dynamic fields

In Langflow, dynamic fields allow inputs to change or appear based on user interactions. You can make an input dynamic by setting dynamic=True. Optionally, setting real_time_refresh=True triggers the update_build_config method to adjust the input's visibility or properties in real time, creating a contextual UI that only displays relevant fields based on the user's choices.

In this example, the operator field triggers updates via real_time_refresh=True. The regex_pattern field is initially hidden and controlled via dynamic=True.


_22
from langflow.io import DropdownInput, StrInput
_22
_22
class RegexRouter(Component):
_22
display_name = "Regex Router"
_22
description = "Demonstrates dynamic fields for regex input."
_22
_22
inputs = [
_22
DropdownInput(
_22
name="operator",
_22
display_name="Operator",
_22
options=["equals", "contains", "regex"],
_22
value="equals",
_22
real_time_refresh=True,
_22
),
_22
StrInput(
_22
name="regex_pattern",
_22
display_name="Regex Pattern",
_22
info="Used if operator='regex'",
_22
dynamic=True,
_22
show=False,
_22
),
_22
]

Implement update_build_config

When a field with real_time_refresh=True is modified, Langflow calls the update_build_config method, passing the updated field name, value, and the component's configuration to dynamically adjust the visibility or properties of other fields based on user input.

This example will show or hide the regex_pattern field when the user selects a different operator.


_10
def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None) -> dict:
_10
if field_name == "operator":
_10
if field_value == "regex":
_10
build_config["regex_pattern"]["show"] = True
_10
else:
_10
build_config["regex_pattern"]["show"] = False
_10
return build_config

Additional Dynamic Field Controls

You can also modify other properties within update_build_config, such as:

  • required: Set build_config["some_field"]["required"] = True/False

  • advanced: Set build_config["some_field"]["advanced"] = True

  • options: Modify dynamic dropdown options.

Tips for Managing Dynamic Fields

When working with dynamic fields, consider the following best practices to ensure a smooth user experience:

  • Minimize field changes: Hide only fields that are truly irrelevant to avoid confusing users.
  • Test behavior: Ensure that adding or removing fields doesn't accidentally erase user input.
  • Preserve data: Use build_config["some_field"]["show"] = False to hide fields without losing their values.
  • Clarify logic: Add info notes to explain why fields appear or disappear based on conditions.
  • Keep it manageable: If the dynamic logic becomes too complex, consider breaking it into smaller components, unless it serves a clear purpose in a single node.

Error handling and logging

In Langflow, robust error handling ensures that your components behave predictably, even when unexpected situations occur, such as invalid inputs, external API failures, or internal logic errors.

Error handling techniques

  • Raise Exceptions: If a critical error occurs, you can raise standard Python exceptions such as ValueError, or specialized exceptions like ToolException. Langflow will automatically catch these and display appropriate error messages in the UI, helping users quickly identify what went wrong.

    _10
    def compute_result(self) -> str:
    _10
    if not self.user_input:
    _10
    raise ValueError("No input provided.")
    _10
    # ...

  • Return Structured Error Data: Instead of stopping a flow abruptly, you can return a Data object containing an "error" field. This approach allows the flow to continue operating and enables downstream components to detect and handle the error gracefully.

    _10
    def run_model(self) -> Data:
    _10
    try:
    _10
    # ...
    _10
    except Exception as e:
    _10
    return Data(data={"error": str(e)})

Improve debugging and flow management

  • Use self.status: Each component has a status field where you can store short messages about the execution result—such as success summaries, partial progress, or error notifications. These appear directly in the UI, making troubleshooting easier for users.


    _10
    def parse_data(self) -> Data:
    _10
    # ...
    _10
    self.status = f"Parsed {len(rows)} rows successfully."
    _10
    return Data(data={"rows": rows})

  • Stop specific outputs with self.stop(...): You can halt individual output paths when certain conditions fail, without affecting the entire component. This is especially useful when working with components that have multiple output branches.


    _10
    def some_output(self) -> Data:
    _10
    if <some condition>:
    _10
    self.stop("some_output") # Tells Langflow no data flows
    _10
    return Data(data={"error": "Condition not met"})

  • Log events: You can log key execution details inside components. Logs are displayed in the "Logs" or "Events" section of the component's detail view and can be accessed later through the flow's debug panel or exported files, providing a clear trace of the component's behavior for easier debugging.


    _10
    def process_file(self, file_path: str):
    _10
    self.log(f"Processing file {file_path}")
    _10
    # ...

Tips for error handling and logging

To build more reliable components, consider the following best practices:

  • Validate inputs early: Catch missing or invalid inputs at the start to prevent broken logic.
  • Summarize with self.status: Use short success or error summaries to help users understand results quickly.
  • Keep logs concise: Focus on meaningful messages to avoid cluttering the UI.
  • Return structured errors: When appropriate, return Data(data={"error": ...}) instead of raising exceptions to allow downstream handling.
  • Stop outputs selectively: Only halt specific outputs with self.stop(...) if necessary, to preserve correct flow behavior elsewhere.

Contribute custom components to Langflow

See How to Contribute to contribute your custom component to Langflow.

Search