How to create a custom component from backend and deploy and enable for all user
Bug Description
Lets suppose i have api which takes text and output text. This will be a post request in python. I have a function for that .
import requests
def call_custom_api(api_url: str, input_text: str, headers: dict = None, timeout: int = 10) -> str: """ Sends a POST request with plain text to the given API URL and returns the plain text response.
Args:
api_url (str): The endpoint URL to send the POST request to.
input_text (str): The text to send in the POST request body.
headers (dict, optional): Headers to include in the request (e.g., authentication, content-type).
timeout (int): Timeout for the request in seconds.
Returns:
str: The plain text response from the API.
"""
try:
# Set default headers if not provided
if headers is None:
headers = {'Content-Type': 'text/plain'}
response = requests.post(api_url, data=input_text.encode('utf-8'), headers=headers, timeout=timeout)
response.raise_for_status() # Raises HTTPError if response code is 4xx or 5xx
return response.text
except requests.exceptions.RequestException as e:
print(f"Error calling API: {e}")
return ""
now i want to add this component in langflow from backend with all description and everything and And when user login to langflow it will be available for all the user. and they can use that component and build some flow on top of it by connecting to other component s. How to achieve it , where to add this code and what changes we need to make and deploy using docker and build the source . and how to show in frontend . I need end to end support for this
Reproduction
Creating custom component from backend and enable for all user
Expected behavior
Creating custom component from backend and enable for all user
Who can help?
No response
Operating System
docker
Langflow Version
latest
Python Version
3.12
Screenshot
No response
Flow File
No response
To create a custom backend component in Langflow that calls your API, make it available to all users, and deploy it with Docker, follow these steps:
1. Write Your Custom Component
Create a Python file for your component (e.g., custom_api_component.py). Place it in a subfolder (like helpers/) under a custom_components directory. Your component should inherit from CustomComponent and implement a build method. Here’s a template based on your function:
from langflow import CustomComponent
from langflow.schema import Message
import requests
class CustomAPIComponent(CustomComponent):
display_name = "Custom API"
description = "Calls a custom API with text input and returns the response."
icon = "🔗"
name = "custom_api_component"
def build_config(self):
return {
"api_url": {
"display_name": "API URL",
"field_type": "str",
"required": True,
},
"headers": {
"display_name": "Headers (JSON)",
"field_type": "str",
"required": False,
"info": "Optional JSON string for headers",
},
"timeout": {
"display_name": "Timeout (seconds)",
"field_type": "int",
"required": False,
"value": 10,
},
}
def build(self, api_url: str, input_text: str, headers: str = None, timeout: int = 10) -> Message:
try:
hdrs = {'Content-Type': 'text/plain'}
if headers:
import json
hdrs.update(json.loads(headers))
response = requests.post(api_url, data=input_text.encode('utf-8'), headers=hdrs, timeout=timeout)
response.raise_for_status()
return Message(text=response.text)
except Exception as e:
return Message(text=f"Error calling API: {e}")
2. Organize the Directory
Your directory structure should look like:
custom_components/
helpers/
custom_api_component.py
The subfolder (e.g., helpers) will appear as a category in the Langflow UI sidebar [1].
3. Docker Integration
Option A: Build a Custom Docker Image
- Add your
custom_componentsfolder to your project. - Modify your Dockerfile to copy this folder and set the environment variable:
FROM langflowai/langflow:latest
WORKDIR /app
COPY custom_components /app/custom_components
ENV LANGFLOW_COMPONENTS_PATH=/app/custom_components
- If your component has extra dependencies (like
requests), add them to yourpyproject.tomland ensure they are installed in the Docker build [2].
Option B: Mount as a Volume
If you want to update components without rebuilding the image, mount the folder:
docker run -d -p 7860:7860 -v /path/to/local/custom_components:/app/custom_components langflowai/langflow:latest
4. Deploy and Verify
- Build and run your Docker container as above.
- When Langflow starts, your custom component will appear in the sidebar under the category you chose (e.g., "Helpers").
- All users will see and be able to use this component in their flows [3].
5. Frontend Display
No extra frontend code is needed if you follow the structure above. Langflow automatically loads and displays custom components in the sidebar for all users. If you want to customize the icon for your category, you can edit the categoryIcons object in src/frontend/src/utils/styleUtils.ts [4].
References:
If you need to support more advanced UI or configuration, you can further customize the build_config method or refer to the contributing guide.
Let me know if you need a more detailed example or run into any issues!
To reply, just mention my name @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
@dosu
this is the test code i have create it is failing
from langflow import CustomComponent from langflow.io import Output, TextInput from langflow.schema import Message import random
class RandomTextAppender(CustomComponent): display_name: str = "Random Text Appender" description: str = "Appends a random phrase to the input text or message." icon: str = "🧩" name: str = "RandomTextAppender"
inputs = [
TextInput(
name="input_value",
display_name="Input Text",
info="Text or Message to append a random phrase to.",
)
]
outputs = [
Output(
name="output_value",
display_name="Appended Message",
method="message_response",
)
]
def message_response(self) -> Message:
input_value = self.input_value
if isinstance(input_value, Message):
base_text = input_value.get_text()
else:
base_text = str(input_value)
suffix = random.choice([
" – and that's a fact!",
" – believe it or not.",
" – more to come soon.",
" – how interesting!",
" – just the beginning!",
])
return Message(text=base_text + suffix)
This is my docker compose
services: langflow-app: build: context: . dockerfile: docker/build_and_push_with_extras.Dockerfile image: langflow-app container_name: langflow-app ports: - "7860:7860" environment: - LANGFLOW_DATABASE_URL=postgresql://langflow:langflow@postgres:5432/langflow - LANGFLOW_SUPERUSER=admin - LANGFLOW_SUPERUSER_PASSWORD=adminpassword - LANGFLOW_SECRET_KEY=23648756921 - LANGFLOW_AUTO_LOGIN=false - LANGFLOW_HOST=0.0.0.0 - LANGFLOW_PORT=7860
# ✅ Add this line to load custom components
- LANGFLOW_COMPONENTS_PATH=/app/custom_components
volumes:
- ./data:/app/data # For persistent data
- ./custom_components:/app/custom_components # ✅ Mount custom components for hot reloads (optional in dev)
depends_on:
- postgres
postgres: image: postgres:16 container_name: postgres environment: - POSTGRES_DB=langflow - POSTGRES_USER=langflow - POSTGRES_PASSWORD=langflow volumes: - ./pgdata:/var/lib/postgresql/data ports: - "5432:5432"
and this is my build_and_push_with_extras.Dockerfile
syntax=docker/dockerfile:1
Keep this syntax directive! It's used to enable Docker BuildKit
################################
BUILDER-BASE
################################ FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
WORKDIR /app
ENV UV_COMPILE_BYTECODE=1 ENV UV_LINK_MODE=copy
RUN apt-get update
&& apt-get upgrade -y
&& apt-get install --no-install-recommends -y
build-essential
git
npm
gcc
&& apt-get clean
&& rm -rf /var/lib/apt/lists/*
RUN --mount=type=cache,target=/root/.cache/uv
--mount=type=bind,source=uv.lock,target=uv.lock
--mount=type=bind,source=README.md,target=README.md
--mount=type=bind,source=pyproject.toml,target=pyproject.toml
--mount=type=bind,source=src/backend/base/README.md,target=src/backend/base/README.md
--mount=type=bind,source=src/backend/base/uv.lock,target=src/backend/base/uv.lock
--mount=type=bind,source=src/backend/base/pyproject.toml,target=src/backend/base/pyproject.toml
uv sync --frozen --no-install-project --no-editable --extra deploy --extra couchbase --extra cassio --extra local --extra clickhouse-connect --extra nv-ingest --extra postgresql
COPY ./src /app/src
COPY src/frontend /tmp/src/frontend
WORKDIR /tmp/src/frontend
RUN --mount=type=cache,target=/root/.npm
npm ci
&& NODE_OPTIONS="--max-old-space-size=4096" npm run build
&& cp -r build /app/src/backend/langflow/frontend
&& rm -rf /tmp/src/frontend
WORKDIR /app COPY ./pyproject.toml /app/pyproject.toml COPY ./uv.lock /app/uv.lock COPY ./README.md /app/README.md
👇 Add this to include your custom components
COPY ./custom_components /app/custom_components
RUN --mount=type=cache,target=/root/.cache/uv
uv sync --frozen --no-editable --extra deploy --extra couchbase --extra cassio --extra local --extra clickhouse-connect --extra nv-ingest --extra postgresql
################################
RUNTIME
################################ FROM python:3.12.3-slim AS runtime
RUN apt-get update
&& apt-get upgrade -y
&& apt-get install -y curl git libpq5 gnupg
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
&& apt-get install -y nodejs
&& apt-get clean
&& rm -rf /var/lib/apt/lists/*
&& useradd user -u 1000 -g 0 --no-create-home --home-dir /app/data
COPY --from=builder --chown=1000 /app/.venv /app/.venv
👇 Also copy the custom components and set environment variable
COPY --from=builder --chown=1000 /app/custom_components /app/custom_components ENV LANGFLOW_COMPONENTS_PATH=/app/custom_components
ENV PATH="/app/.venv/bin:$PATH"
LABEL org.opencontainers.image.title=langflow LABEL org.opencontainers.image.authors=['Langflow'] LABEL org.opencontainers.image.licenses=MIT LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow
USER user WORKDIR /app
ENV LANGFLOW_HOST=0.0.0.0 ENV LANGFLOW_PORT=7860
CMD ["langflow", "run"]
Why it is not working and failing
Your custom component is likely failing because it does not implement the required build method. In Langflow, every custom component must inherit from CustomComponent and define a build method, which is the entry point for the component's execution and field definitions. The message_response method alone is not sufficient—Langflow expects a build method to exist and match the component's outputs and inputs [docs].
Here’s how you can fix your component:
from langflow import CustomComponent
from langflow.io import Output, TextInput
from langflow.schema import Message
import random
class RandomTextAppender(CustomComponent):
display_name: str = "Random Text Appender"
description: str = "Appends a random phrase to the input text or message."
icon: str = "🧩"
name: str = "RandomTextAppender"
inputs = [
TextInput(
name="input_value",
display_name="Input Text",
info="Text or Message to append a random phrase to.",
)
]
outputs = [
Output(
name="output_value",
display_name="Appended Message",
method="build", # This should match the method name below
)
]
def build(self, input_value) -> Message:
if isinstance(input_value, Message):
base_text = input_value.get_text()
else:
base_text = str(input_value)
suffix = random.choice([
" – and that's a fact!",
" – believe it or not.",
" – more to come soon.",
" – how interesting!",
" – just the beginning!",
])
return Message(text=base_text + suffix)
Key points:
- The output’s
methodshould be"build"to match the method name. - The
buildmethod must accept the input(s) as arguments. - Remove the
message_responsemethod unless you want to define multiple outputs.
Docker and directory setup:
Your Docker and volume setup looks correct. Just ensure your custom component is in a subfolder (e.g., custom_components/helpers/random_text_appender.py) and that LANGFLOW_COMPONENTS_PATH points to /app/custom_components [docs].
If it still fails:
Check the langflow.log file or Docker logs for error messages about component loading. Langflow will skip components with errors and log the reason [docs].
If you share the specific error message from the logs, I can help you further debug the issue.
To reply, just mention my name @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
@dosu I am not sure why custom component is not working , am i not building it from source thats why or what . I want to give you my docker file and compose.yml . And let me know what change i should do so that things can work in canvas it can wire and also i want to make changes in frontend . The idea is to build from source and add my components custom to langflow in python
My docker file is as build_and_push_with_extras.Dockerfile
syntax=docker/dockerfile:1
################################
BUILDER-BASE
################################ FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
WORKDIR /app
ENV UV_COMPILE_BYTECODE=1 ENV UV_LINK_MODE=copy
Install system dependencies
RUN apt-get update
&& apt-get upgrade -y
&& apt-get install --no-install-recommends -y
build-essential
git
npm
gcc
&& apt-get clean
&& rm -rf /var/lib/apt/lists/*
Install backend dependencies from lock files
RUN --mount=type=cache,target=/root/.cache/uv
--mount=type=bind,source=uv.lock,target=uv.lock
--mount=type=bind,source=README.md,target=README.md
--mount=type=bind,source=pyproject.toml,target=pyproject.toml
--mount=type=bind,source=src/backend/base/README.md,target=src/backend/base/README.md
--mount=type=bind,source=src/backend/base/uv.lock,target=src/backend/base/uv.lock
--mount=type=bind,source=src/backend/base/pyproject.toml,target=src/backend/base/pyproject.toml
uv sync --frozen --no-install-project --no-editable
--extra deploy --extra couchbase --extra cassio --extra local --extra clickhouse-connect --extra nv-ingest --extra postgresql
Copy everything (source, UI, components)
COPY ./src /app/src
COPY src/frontend /tmp/src/frontend WORKDIR /tmp/src/frontend
Build frontend
RUN --mount=type=cache,target=/root/.npm
npm ci
&& NODE_OPTIONS="--max-old-space-size=4096" npm run build
&& cp -r build /app/src/backend/langflow/frontend
&& rm -rf /tmp/src/frontend
Install backend from your current source
WORKDIR /app
COPY ./pyproject.toml /app/pyproject.toml COPY ./uv.lock /app/uv.lock COPY ./README.md /app/README.md COPY ./custom_components /app/custom_components
RUN --mount=type=cache,target=/root/.cache/uv
uv sync --frozen --no-editable --extra deploy --extra couchbase --extra cassio --extra local --extra clickhouse-connect --extra nv-ingest --extra postgresql
################################
RUNTIME
################################ FROM python:3.12.3-slim AS runtime
RUN apt-get update
&& apt-get upgrade -y
&& apt-get install -y curl git libpq5 gnupg
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
&& apt-get install -y nodejs
&& apt-get clean
&& rm -rf /var/lib/apt/lists/*
&& useradd user -u 1000 -g 0 --no-create-home --home-dir /app/data
COPY --from=builder --chown=1000 /app/.venv /app/.venv COPY --from=builder --chown=1000 /app/custom_components /app/custom_components
ENV LANGFLOW_COMPONENTS_PATH=/app/custom_components
ENV PATH="/app/.venv/bin:$PATH"
LABEL org.opencontainers.image.title=langflow LABEL org.opencontainers.image.authors=['Langflow'] LABEL org.opencontainers.image.licenses=MIT LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow
USER user WORKDIR /app
ENV LANGFLOW_HOST=0.0.0.0 ENV LANGFLOW_PORT=7860
CMD ["langflow", "run"]
Also Attaching the docker compose yaml , which is in parent directory services: langflow-app: build: context: . dockerfile: docker/build_and_push_with_extras.Dockerfile image: langflow-app container_name: langflow-app ports: - "7860:7860" environment: - LANGFLOW_DATABASE_URL=postgresql://langflow:langflow@postgres:5432/langflow - LANGFLOW_SUPERUSER=admin - LANGFLOW_SUPERUSER_PASSWORD=adminpassword - LANGFLOW_SECRET_KEY=23648756921 - LANGFLOW_AUTO_LOGIN=false - LANGFLOW_HOST=0.0.0.0 - LANGFLOW_PORT=7860 - LANGFLOW_COMPONENTS_PATH=/app/custom_components volumes: - ./data:/app/data - ./custom_components:/app/custom_components depends_on: - postgres
postgres: image: postgres:16 container_name: postgres environment: - POSTGRES_DB=langflow - POSTGRES_USER=langflow - POSTGRES_PASSWORD=langflow volumes: - ./pgdata:/var/lib/postgresql/data ports: - "5432:5432"
Also sharing the custom component directory structure and Code
He is the directory structure
#------------- also sharing the code i have written for custom compnent i just want to wire it on canvas and get output something like that
from langflow import CustomComponent from langflow.inputs import HandleInput from langflow.io import Output from langflow.schema.message import Message import random
class RandomTextAppender(CustomComponent): display_name: str = "Random Text Appender" description: str = "Appends a random phrase to text or message from any upstream component." icon = "🧩" name = "RandomTextAppender"
inputs = [
HandleInput(
name="input_value",
display_name="Text or Message",
input_types=["Message", "str"],
required=True,
)
]
outputs = [
Output(
name="output_value",
display_name="Modified Message",
method="build_results",
)
]
async def build_results(self) -> Message:
print("⚠️ DEBUG: Entering build_results")
print("⚠️ DEBUG: Component attributes:", dir(self))
try:
input_value = self.get_input("input_value")
print("⚠️ DEBUG: input_value =", input_value)
except Exception as e:
print("❌ ERROR getting input_value:", str(e))
raise ValueError(f"[RandomTextAppender] Failed to get input: {e}")
# Convert to string if needed
base_text = input_value.text if isinstance(input_value, Message) else str(input_value)
# Add random suffix
suffix = random.choice([
" – and that's a fact!",
" – more to come soon.",
" – believe it or not.",
" – stay tuned!",
])
final_text = base_text + suffix
print("✅ DEBUG: Final message:", final_text)
return Message(text=final_text)
what do you suggest am i not building the docker of lanflow from source , if so give me the complete docker file and docker compose to solve this problem
@yashugupta786 You're on the right track, as the easiest way is to use LANGFLOW_COMPONENTS_PATH.
This parameter was bugged between versions 1.5.0 and 1.5.0post2, but it's been fixed in main and future releases.
The structure within the folder should follow this configuration: https://docs.langflow.org/components-custom-components#directory-structure-requirements