Overview
In Langflow, people assemble flows from components on a browser canvas. An agent handles the parts around the canvas from a terminal: installing and starting the server, configuring it through environment variables, calling flows over HTTP, moving flow JSON between instances and into git, running a flow file headlessly with lfx, registering a project as an MCP server, and upgrading.
Instructions
Installation
# Python package, inside a virtual environment
uv venv langflow-venv
source langflow-venv/bin/activate
uv pip install langflow # langflow-base installs the same app without provider bundles
uv run langflow run # first start can take a few minutes
The server listens on http://127.0.0.1:7860. A quick container without persistent storage:
# LANGFLOW_SUPERUSER_PASSWORD is chosen by the user; the image refuses to start without it
docker run -p 7860:7860 \
-e LANGFLOW_SUPERUSER_PASSWORD="$LANGFLOW_SUPERUSER_PASSWORD" \
langflowai/langflow:latest
curl -s http://localhost:7860/health_check
# {"status":"ok","chat":"ok","db":"ok"}
Official images set LANGFLOW_AUTO_LOGIN=false, so the superuser password is mandatory and the old default value langflow is rejected. The default superuser name is langflow.
Deploy with Docker Compose and PostgreSQL
The repository ships a Compose file with PostgreSQL and named volumes for data.
git clone https://github.com/langflow-ai/langflow.git
cd langflow/docker_example
printf 'LANGFLOW_SUPERUSER_PASSWORD=%s\n' "$(openssl rand -hex 16)" > .env
docker compose up -d
docker compose ps
For anything beyond a local test, pin image: langflowai/langflow:1.12.4 instead of latest, change the PostgreSQL credentials in the file, and remove the published 5432 port.
Configure the server
Settings come from CLI options, environment variables or a .env file; a CLI option overrides the variable of the same name.
| Variable | Default | Purpose |
|---|---|---|
LANGFLOW_HOST, LANGFLOW_PORT | localhost, 7860 | Bind address and port (a free port is chosen if busy) |
LANGFLOW_AUTO_LOGIN | True (package), false (Docker) | False requires sign-in and API keys |
LANGFLOW_SUPERUSER, LANGFLOW_SUPERUSER_PASSWORD | langflow, none | Admin account created at startup |
LANGFLOW_SECRET_KEY | generated | Encrypts stored credentials; set it explicitly in production |
LANGFLOW_DATABASE_URL | SQLite file | For example postgresql://langflow:s3cure@postgres:5432/langflow |
LANGFLOW_CONFIG_DIR | depends on the OS | Directory for logs, file storage and secret keys |
LANGFLOW_API_KEY_SOURCE | db | env validates requests against LANGFLOW_API_KEY |
LANGFLOW_LOAD_FLOWS_PATH | unset | Directory of flow JSON loaded at startup (needs auto-login) |
LANGFLOW_ENABLE_SUPERUSER_CLI | True | Set False to disable langflow superuser |
python3 -c "from secrets import token_urlsafe; print(f'LANGFLOW_SECRET_KEY={token_urlsafe(32)}')" >> langflow.env
printf 'LANGFLOW_AUTO_LOGIN=False\nLANGFLOW_ENABLE_SIGNUP=False\n' >> langflow.env
printf 'LANGFLOW_SUPERUSER_PASSWORD=%s\n' "$(openssl rand -hex 16)" >> langflow.env
uv run langflow run --env-file langflow.env --host 0.0.0.0 --port 7860 --backend-only
--backend-only starts the API without the visual editor. Other CLI commands: langflow api-key, langflow superuser, langflow migration and langflow --version.
Authenticate
Requests carry a Langflow API key in the x-api-key header. Keys are created in the editor under Settings → Langflow API Keys, or on the server by a superuser:
uv run langflow api-key
For unattended deployments, set LANGFLOW_API_KEY_SOURCE=env and LANGFLOW_API_KEY to a generated secret. That single key then has superuser rights.
export LANGFLOW_URL="http://localhost:7860" # LANGFLOW_API_KEY comes from one of the methods above
curl -s "$LANGFLOW_URL/api/v1/version"
curl -s "$LANGFLOW_URL/api/v1/flows/?get_all=true&header_flows=true" \
-H "x-api-key: $LANGFLOW_API_KEY" | jq -r '.[] | "\(.id) \(.name)"'
Run a flow
FLOW_ID="359cd752-07ea-46f2-9d3b-a4407ef618da" # flow UUID or its endpoint name
curl -s -X POST "$LANGFLOW_URL/api/v1/run/$FLOW_ID?stream=false" \
-H "Content-Type: application/json" \
-H "x-api-key: $LANGFLOW_API_KEY" \
-d '{
"input_value": "What is your refund policy for annual plans?",
"input_type": "chat",
"output_type": "chat",
"session_id": "customer-4821",
"tweaks": {"ChatOutput-6zcZt": {"should_store_message": true}}
}' | jq -r '.outputs[0].outputs[0].results.message.text'
| Field | Meaning |
|---|---|
input_value | Text passed to the flow's input component |
input_type, output_type | chat or text for input; chat, any or debug for output |
session_id | Conversation id; reuse it to keep chat memory between calls |
tweaks | One-time overrides keyed by component id, such as OpenAIModel-d1wOZ |
?stream=true | Streams token events and a final end event |
Secrets and per-request values can be injected as global variables without storing them in Langflow: add headers of the form X-LANGFLOW-GLOBAL-VAR-OPENAI_API_KEY: .... A flow with a Webhook component is started with POST /api/v1/webhook/$FLOW_ID and any JSON body; the reply only confirms that the run started.
import os
import requests
url = f"{os.environ['LANGFLOW_URL']}/api/v1/run/{os.environ['FLOW_ID']}"
headers = {"x-api-key": os.environ["LANGFLOW_API_KEY"]}
payload = {"input_value": "Summarize ticket 88213", "input_type": "chat",
"output_type": "chat", "session_id": "helpdesk-88213"}
response = requests.post(url, headers=headers, json=payload, timeout=120)
response.raise_for_status()
print(response.json()["outputs"][0]["outputs"][0]["results"]["message"]["text"])
Export and import flows
# Export selected flows as a ZIP of JSON files
curl -s -X POST "$LANGFLOW_URL/api/v1/flows/download/" \
-H "Content-Type: application/json" -H "x-api-key: $LANGFLOW_API_KEY" \
-d '["359cd752-07ea-46f2-9d3b-a4407ef618da", "92f9a4c5-cfc8-4656-ae63-1f0881163c28"]' \
--output langflow-flows.zip
# Export a whole project
curl -s "$LANGFLOW_URL/api/v1/projects/" -H "x-api-key: $LANGFLOW_API_KEY" | jq -r '.[] | "\(.id) \(.name)"'
curl -s "$LANGFLOW_URL/api/v1/projects/download/1415de42-8f01-4f36-bf34-539f23e47466" \
-H "x-api-key: $LANGFLOW_API_KEY" --output langflow-project.zip
# Import one flow file into a project
curl -s -X POST "$LANGFLOW_URL/api/v1/flows/upload/?folder_id=1415de42-8f01-4f36-bf34-539f23e47466" \
-H "x-api-key: $LANGFLOW_API_KEY" \
-F "file=@faq-assistant.json;type=application/json"
An exported flow references global variables by name. The target instance needs variables with the same names, or the flow fails at run time.
Run a flow file without the server
lfx executes flow JSON statelessly, with no database and no editor. It is included with Langflow 1.6 and later, or installed alone with uv pip install lfx.
lfx requirements faq-assistant.json # Python packages the flow's components need
uv run lfx run faq-assistant.json "What is your refund policy?" --format json | jq '.result'
export LANGFLOW_API_KEY="$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')"
uv run lfx serve faq-assistant.json # prints the flow id, serves http://127.0.0.1:8000
curl -s -X POST "http://127.0.0.1:8000/flows/c1dab29d-3364-58ef-8fef-99311d32ee42/run" \
-H "Content-Type: application/json" -H "x-api-key: $LANGFLOW_API_KEY" \
-d '{"input_value": "What is your refund policy?"}'
Expose flows to MCP clients
Every project is an MCP server at /api/v1/mcp/project/$PROJECT_ID/streamable, and each flow with a Chat Output component becomes a tool. Generate the client entry instead of typing the key into a file by hand:
PROJECT_ID="1415de42-8f01-4f36-bf34-539f23e47466"
jq -n --arg url "$LANGFLOW_URL/api/v1/mcp/project/$PROJECT_ID/streamable" --arg key "$LANGFLOW_API_KEY" \
'{mcpServers: {"langflow-support": {command: "uvx",
args: ["mcp-proxy", "--transport", "streamablehttp", "--headers", "x-api-key", $key, $url]}}}'
Merge the printed object into the client's MCP configuration, such as Cursor's mcp.json.
Upgrade
# 1. Export every project as shown above, then dump the database
docker compose exec -T postgres pg_dump -U langflow langflow > "langflow-db-$(date +%Y%m%d).sql"
# 2. Set the new image tag in docker-compose.yml, then
docker compose pull
docker compose up -d
# Python installs: uv pip install langflow -U
Pending database migrations run at startup. If startup reports a schema mismatch, uv run langflow migration previews the required changes without applying them.
Examples
Example 1: Call a flow and keep the conversation
Request: "Ask our FAQ Assistant flow about refunds, then ask a follow-up in the same conversation."
ask() {
curl -s -X POST "$LANGFLOW_URL/api/v1/run/faq-assistant?stream=false" \
-H "Content-Type: application/json" -H "x-api-key: $LANGFLOW_API_KEY" \
-d "$(jq -n --arg q "$1" '{input_value: $q, input_type: "chat", output_type: "chat", session_id: "customer-4821"}')" \
| jq -r '.outputs[0].outputs[0].results.message.text'
}
ask "Can I get a refund on an annual plan?"
ask "And how long does it take to arrive?"
Result:
Annual plans can be refunded in full within 30 days of purchase.
Refunds are returned to the original payment method within 5 to 7 business days.
The second answer resolves "it" because both calls share session_id.
Example 2: Move a project to a new instance
Request: "Copy every flow from the old Langflow server to the new one before we switch DNS."
curl -s "https://flows-old.northwind.dev/api/v1/projects/download/1415de42-8f01-4f36-bf34-539f23e47466" \
-H "x-api-key: $LANGFLOW_OLD_API_KEY" --output support-flows.zip
curl -s -X POST "https://flows.northwind.dev/api/v1/projects/upload/" \
-H "x-api-key: $LANGFLOW_API_KEY" \
-F "file=@support-flows.zip" | jq -r '.[] | "\(.id) \(.name)"'
Result: the upload answers with the flows it created on the new instance:
8d2f6c1e-5b7a-4f3d-9a60-2e1c7b4d9f05 FAQ Assistant
41b9e7a3-0c6d-4e82-b5f1-7a3d2c9e6b18 Ticket Router
Compare these ids with the ones callers use before switching traffic. Global variables are not part of the archive and have to be created on the new instance with the same names.
Guidelines
- Building flows is a browser task: components are placed and wired on the canvas by a person. An agent can generate or edit flow JSON, but should validate it by importing it and running it once.
- Auto-login is for local use only: with
LANGFLOW_AUTO_LOGIN=Trueevery visitor acts as superuser. Any shared or public server needsFalse, a strong superuser password and a fixedLANGFLOW_SECRET_KEY. - API keys inherit the creator's rights: a key made by a superuser can read and change every flow of that user. Keys created with
langflow api-keyare always superuser keys. - Exports can contain secrets: a literal key typed into a component field is written into the exported JSON. Store credentials as global variables so only the variable name is exported, and review files before committing them.
- Database location: the default SQLite file lives inside the Python environment, so a new virtual environment starts empty. Set
LANGFLOW_DATABASE_URLto PostgreSQL or an absolute SQLite path such assqlite:////var/lib/langflow/langflow.db. Switching databases copies nothing; export flows first and import them afterwards. - Migrations:
langflow migration --fixcan delete data. Runlangflow migrationfirst and keep a database backup. - Missing components after an upgrade: since 1.12,
langflowinstalls only a curated set of provider bundles. The error names the missing package; install it, for exampleuv pip install lfx-exa. - Webhooks need a key too: webhook endpoints require the API key unless
LANGFLOW_WEBHOOK_AUTH_ENABLE=False, which should stay enabled outside trusted networks. - Multiple workers: running
--workersabove 1 needs a shared Redis job queue. Keep one worker unless that is configured. - When not to use: if nobody needs a visual editor, calling a model SDK or an agent framework directly has fewer moving parts. For production serving of finished flows,
lfx serveis lighter than the full server.