fix: persist Langflow database across container restarts#1208
Merged
mpawlow merged 7 commits intorelease-0.4.0from Mar 23, 2026
Merged
Conversation
This comment has been minimized.
This comment has been minimized.
2 tasks
Fixes #1127 - Langflow flow edits no longer lost after restart ## Problem Flow edits made in Langflow UI were being lost after container restart. The langflow service only mounted /app/flows but Langflow stores its SQLite database at /root/.langflow/ by default, which was ephemeral. ## Solution 1. Add persistent volume for Langflow data directory: - Mount ${LANGFLOW_DATA_PATH:-./langflow-data} to /root/.langflow 2. Explicitly set LANGFLOW_DATABASE_URL to ensure database location 3. Document the new LANGFLOW_DATA_PATH in .env.example ## Testing - Verified volume mount configuration - Database URL format: sqlite:////root/.langflow/langflow.db Closes #1127
Issue - #1127 Summary - User-made edits to Langflow flows were silently discarded on every container restart. - Two root causes were identified and corrected: - (1) The Langflow data volume was mounted to the wrong path inside the container. - (2) The LANGFLOW_LOAD_FLOWS_PATH mechanism performed a blind upsert of all flows on every startup, overwriting any changes made in the Langflow UI. Docker / Infrastructure - Corrected the Langflow data volume mount target from /root/.langflow to /app/langflow-data in docker-compose.yml - Replaced LANGFLOW_LOAD_FLOWS_PATH env var with LANGFLOW_CONFIG_DIR=/app/langflow-data so Langflow resolves its config and database from the persisted volume - Updated LANGFLOW_DATABASE_URL to reference the new path (sqlite:////app/langflow-data/langflow.db) - Pre-created /app/langflow-data in Dockerfile.langflow during image build to ensure named Docker volumes are initialised with the correct ownership for the non-root container user - Added langflow-data/ directory with a .gitkeep file; updated .gitignore to track the directory stub while ignoring its contents Backend — Flow Bootstrapping - Added FlowsService.ensure_flows_exist(): a create-only startup routine that checks each configured flow ID against the Langflow API and creates missing flows from their JSON files, without ever patching or overwriting an existing flow - Replaced the LANGFLOW_LOAD_FLOWS_PATH blind-upsert behaviour with a call to ensure_flows_exist() inside startup_tasks() in src/main.py Makefile - Extended the factory-reset target to remove the langflow-data/ directory alongside opensearch-data/ and config/ Code Cleanup - Removed trailing whitespace throughout src/services/flows_service.py Builds on #1129
Issue - #1127 Summary - Propagated LANGFLOW_DATA_PATH to all locations that reference OPENSEARCH_DATA_PATH CI / Test Infrastructure - Added langflow-data to the Docker container cleanup command in test-e2e.yml and test-integration.yml, ensuring CI runners start each run with a clean Langflow database - Added LANGFLOW_DATA_PATH=./langflow-data to frontend/.env.test.example alongside the existing OPENSEARCH_DATA_PATH entry - Added a langflow-data directory cleanup block to tests/conftest.py that mirrors the existing opensearch-data teardown, so integration tests run against a fresh Langflow DB Documentation - Added a LANGFLOW_DATA_PATH row to the Langflow settings table in docs/docs/reference/configuration.mdx, documenting the default value and that flow edits are lost without this volume TUI — Configuration Fields - Added a langflow_data_path ConfigField to the Langflow section in config_fields.py with a file picker placeholder and a default of $HOME/.openrag/data/langflow-data TUI — Env Manager - Added langflow_data_path field to the EnvConfig dataclass in env_manager.py - Added "LANGFLOW_DATA_PATH": "langflow_data_path" entry to _env_attr_map() so the variable is loaded from and written to .env files - Added LANGFLOW_DATA_PATH write in save_env_file() immediately after the OPENSEARCH_DATA_PATH write TUI — Config Screen - Added langflow_data_path to SPECIAL_FIELDS in config.py - Added _render_langflow_data_path() renderer with a "Pick…" directory picker button, matching the _render_opensearch_data_path() pattern - Added action_pick_langflow_data_path() action implementing the textual-fspicker directory picker flow - Wired the pick-langflow-data-btn button in on_pressed and added the _langflow_data_pick_callback fallback handler in on_screen_dismissed
Issue - #1127 Summary - Fixed Langflow data directory persistence and bind-mount ownership across container restarts Container & Entrypoint - Added docker-entrypoint-langflow.sh that runs as root, chowns /app/langflow-data to uid=1000, then drops privileges and execs the main process — mirrors the pattern used by official database images - Updated Dockerfile.langflow to switch to USER root, copy the entrypoint script, set it as ENTRYPOINT, and simplified the RUN layer - Added # syntax=docker/dockerfile:1.4 directive to Dockerfile.langflow Repository & Git Ignore - Removed langflow-data/.gitkeep and replaced the selective .gitignore pattern (/langflow-data/* + !.gitkeep) with a blanket langflow-data/ ignore entry Makefile - Added ensure-langflow-data target that creates the langflow-data bind-mount directory on the host before Docker starts (prevents Docker from creating it as root) - Added ensure-langflow-data as a prerequisite to dev, dev-cpu, dev-local, dev-local-cpu, dev-local-build-lf, dev-local-build-lf-cpu, dev-branch, dev-branch-cpu, restart-dev, test-ci, and test-ci-local - Updated factory-reset to fully remove the langflow-data directory (rm -rf langflow-data) instead of only clearing its contents
Issue - #1127 Summary - Removed Langflow data directory cleanup from test setup Test Infrastructure - Removed the block in conftest.py that deleted the Langflow data directory (LANGFLOW_DATA_PATH) before tests ran, as this cleanup is no longer appropriate given that the Langflow database is now persisted across container restarts.
Issue - #1127 Summary - Persisted Langflow database and flow configurations across container restarts by replacing the blind upsert startup mechanism with a create-only flow seeding approach. Docker / Container Changes - Removed the custom docker-entrypoint-langflow.sh entrypoint script, which ran chown as root before dropping to uid=1000; the base Langflow image already owns /app as uid=1000, so the privilege escalation was unnecessary. - Simplified Dockerfile.langflow by removing the USER root switch, entrypoint script copy, and the ENTRYPOINT override; the image now runs its default langflow run command directly. - Updated docker-compose.yml to resolve LANGFLOW_DATABASE_URL from the environment with a SQLite fallback (${LANGFLOW_DATABASE_URL:-sqlite:////app/langflow-data/langflow.db}), allowing operators to substitute a PostgreSQL URL without rebuilding the image. - Added LANGFLOW_DATABASE_URL to .env.example with documentation on overriding for production PostgreSQL deployments. Kubernetes / Helm Changes - Replaced the LANGFLOW_LOAD_FLOWS_PATH env var with LANGFLOW_CONFIG_DIR in the Langflow Helm deployment template to align with the new startup flow seeding approach. Backend: Flow Seeding & Reset Detection - Updated FlowsService.ensure_flows_exist() to return a set[str] of flow type names that were newly created during the current startup, rather than returning None. - Added handling for unexpected non-404 HTTP status codes when checking whether a flow exists; logs a warning and skips creation to avoid overwriting existing data. - Updated startup_tasks() in src/main.py to capture the set of newly created flows from ensure_flows_exist(). - Filtered out newly seeded flows from the check_flows_reset() result so that freshly created flows (which match their JSON definition by design) are not incorrectly flagged as having been externally reset. - Upgraded the log level for ensure_flows_exist() failures from warning to error to better surface critical startup failures.
Issue - #1127 Summary - Fixed Langflow data directory permissions for CI and E2E test environments CI Test Pipeline (Makefile) - Added chmod 777 langflow-data before the test run in both test-ci and test-ci-local targets to ensure the langflow-data directory is world-writable prior to container startup E2E Test Setup (scripts/setup-e2e.sh) - Added pre-creation of the langflow-data directory with world-writable permissions (777) before infrastructure starts, ensuring the Langflow container (UID 1000) and the CI runner (UID 1001) can both access it regardless of Docker's :U flag behavior
3a5b98b to
47cb992
Compare
Contributor
|
Build successful! ✅ |
Wallgau
approved these changes
Mar 23, 2026
Collaborator
Wallgau
left a comment
There was a problem hiding this comment.
changes were approved for main, so just origin branch here, LGTM
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue
Reference Pull Request