* feat(execution): scaffold execution package with test isolation fixture * feat(execution): add core types (Unit, StepResult, RunComplete) * feat(execution): add Executor abstract base class * feat(execution): add identity partition function * feat(execution): add executor registry (register/get only) * feat(execution): add InProcessExecutor (streaming + legacy passthrough) * feat(execution): add Coordinator with streaming run + run_to_completion * feat(execution): default singleton with in-process pre-registered + setter * feat(execution): route Graph.arun through coordinator (seam #1) * feat(execution): route flow_executor through coordinator (seam #2) * feat(execution): route CLI and run/base through coordinator (seam #3) * feat(execution): route Loop subgraph through coordinator (seam #4) * fix(execution): explicit legacy dispatch flag, forward fallback_to_env_vars, real-graph concurrency tests * refactor(execution): add Coordinator.stream helper, lift imports, replace em-dash * test(execution): shared simple_graph fixture, reset_default_coordinator helper, real-executor loop tests, behavior assertions * refactor(execution): wrap default singletons in _Defaults holder, drop noqas * feat(execution): make executor seam pluggable via lfx services Introduce an ExecutorService that owns the registry and the default coordinator, discovered through the standard lfx ServiceManager (parity with cache, database, storage, etc). Add an executor_kind setting so the default kind can be configured without touching code, and an lfx.executors entry-point group for third-party executors. Entry-point discovery refuses to overwrite an existing kind so an installed package cannot silently replace the built-in in-process executor; explicit replacement still works through ExecutorService.register(). The lfx.execution public API (get_default_coordinator, get_default_registry, set_default_coordinator, reset_default_coordinator) now resolves through the service manager but keeps the same surface, so existing call sites in Graph.arun, flow_executor, the CLI, run/base, and loop_utils are unchanged. Also surface root-cause tracebacks in lfx.services.deps.get_service: the helper still returns None on failure (callers like get_db_service rely on that), but it now logs the exception so init failures stop disappearing into the void. * test(execution): contract suite, cancellation guarantees, seam docstrings Robustness pass on the execution seam after using it to integrate an external executor end-to-end. Four things this pins down: 1. Reusable executor contract suite - tests/unit/execution/test_executor_contract.py - ExecutorContract with 7 universal seam guarantees: kind shape, execute() returns an AsyncIterator, stream ends with exactly one RunComplete, instance is reusable across runs, concurrent runs are isolated, consumer cancellation does not hang or leak, execute() signature is stable. - TestInProcessExecutorContract subclasses and provides fixtures. Downstream executors (stepflow, future remote/sandbox) get the same battery by subclassing and overriding two fixtures. 2. Cancellation/cleanup correctness - tests/unit/execution/test_cancellation.py - InProcessExecutor wraps graph.async_start() in try/finally with explicit aclose so consumer aclose cascades to the underlying graph generator. Previously the inner generator was abandoned and only finalized on a GC pass: a real leak for executors holding subprocesses or sockets. - Coordinator.run and Coordinator.stream propagate aclose the same way so the full chain (consumer -> coordinator -> executor -> graph) cleans up deterministically. 3. Documented seam contracts - Unit.runtime_options: free-form bag, "_"-prefixed keys reserved for executor-internal flags, common in-process keys listed. - StepResult.payload: untyped on purpose; each executor defines its own event vocabulary; consumers normalize at consumption site. - RunComplete.outputs: only the legacy in-process path populates it; streaming consumers should collect from StepResult.payload. - Executor ABC: lifecycle (shared instance, must be reusable, must tolerate concurrent execute() calls and consumer aclose). 4. Coordinator-routed E2E suite - tests/unit/execution/test_coordinator_e2e.py - Real Graph through Coordinator -> registry -> InProcessExecutor chain. - Asserts payload shape, RunComplete never leaks to stream() consumers, dispatch routes to configured kind, registry returns same instance. Full execution suite: 63 passing. flow_executor coordinator test: passing. * fix(execution): close async generators on early exit and harden seam tests - run_to_completion and Coordinator.stream wrap iteration in contextlib.aclosing so the underlying generator is finalized when the loop returns or raises early - execute_loop_body wraps its stream in aclosing for the same mid-iteration guarantee - drop the unused inputs param from Coordinator.stream; the streaming path reads initial_inputs from runtime_options, so inputs was a silent no-op, and document it - test_coordinator_uses_settings_executor_kind uses monkeypatch + a finalizer so a mid-test failure can't poison session settings - test_registry_returns_same_executor_instance_across_runs builds a fresh graph per run - test_set_default_coordinator_overrides_singleton restores the singleton afterward * fix(execution): register ExecutorService factory and update seam test mocks - register ExecutorServiceFactory in register_all_service_factories so EXECUTOR_SERVICE resolves at app startup; without it the seam raised NoFactoryRegisteredError across integration and mcp tests - test_base.py graph.async_start mocks now default the leading positional param (the seam calls async_start with inputs as a keyword), fixing the 'missing 1 required positional argument' failures - add executor_kind to the settings composition EXPECTED_FIELDS set * fix(execution): reject non-Executor entry-point plugins; doc corrections - ExecutorService discovery skips a loaded entry-point object that is not an Executor instance instead of registering it and failing only at execute() time - Coordinator.run docstring notes the single-Unit / single-RunComplete assumption that identity_partition currently guarantees - correct two stale docstrings: Unit's session_id is honored only on the legacy passthrough path, and ExecutorService.teardown no longer claims the service manager keeps the cached instance * fix(lfx): reset factory-registered flag on ServiceManager teardown teardown() emptied self.factories but left factory_registered set, so get_service()'s lazy re-registration was skipped and later lookups raised NoFactoryRegisteredError. Once Graph.arun started routing through the executor service, that surfaced as intermittent flow-execution 500s in the backend unit suite whenever a sibling test had torn the global manager down. * test(loop): accept executor kwargs in subgraph async_start mock The loop body now runs its subgraph through get_default_coordinator().stream, so InProcessExecutor calls async_start with inputs/max_iterations/config/ reset_output_values/fallback_to_env_vars alongside event_manager. The mock only accepted event_manager and raised TypeError on the extra kwargs. Widen it to **_kwargs while still capturing event_manager for the assertion.
Langflow is a powerful platform for building and deploying AI-powered agents and workflows. It provides developers with both a visual authoring experience and built-in API and MCP servers that turn every workflow into a tool that can be integrated into applications built on any framework or stack. Langflow comes with batteries included and supports all major LLMs, vector databases and a growing library of AI tools.
✨ Highlight features
- Visual builder interface to quickly get started and iterate.
- Source code access lets you customize any component using Python.
- Interactive playground to immediately test and refine your flows with step-by-step control.
- Multi-agent orchestration with conversation management and retrieval.
- Deploy as an API or export as JSON for Python apps.
- Deploy as an MCP server and turn your flows into tools for MCP clients.
- Observability with LangSmith, LangFuse and other integrations.
- Enterprise-ready security and scalability.
🖥️ Langflow Desktop
Langflow Desktop is the easiest way to get started with Langflow. All dependencies are included, so you don't need to manage Python environments or install packages manually. Available for Windows and macOS.
⚡️ Quickstart
Install locally (recommended)
Requires Python 3.10–3.14 and uv (recommended package manager).
Install
From a fresh directory, run:
uv pip install langflow -U
The latest Langflow package is installed. For more information, see Install and run the Langflow OSS Python package.
Run
To start Langflow, run:
uv run langflow run
Langflow starts at http://127.0.0.1:7860.
That's it! You're ready to build with Langflow! 🎉
📦 Other install options
Run from source
If you've cloned this repository and want to contribute, run this command from the repository root:
make run_cli
For more information, see DEVELOPMENT.md.
Docker
Start a Langflow container with default settings:
docker run -p 7860:7860 langflowai/langflow:latest
Langflow is available at http://localhost:7860/. For configuration options, see the Docker deployment guide.
🛡️ Security
For security information, see our Security Policy.
🚀 Deployment
Langflow is completely open source and you can deploy it to all major deployment clouds. To learn how to deploy Langflow, see our Langflow deployment guides.
⭐ Stay up-to-date
Star Langflow on GitHub to be instantly notified of new releases.
👋 Contribute
We welcome contributions from developers of all levels. If you'd like to contribute, please check our contributing guidelines and help make Langflow more accessible.