LangFlow Import/Export: Moving Flows Between Environments
You built a flow in LangFlow on your laptop. It works. The retrieval chain is tuned, the prompt template is dialed in, the agent routes correctly between three tools. Now you need it running on a colleague's machine, or on staging, or in production behind a different API key and a different vector store. This is the moment most LangFlow tutorials skip, and it's exactly where teams lose a day to broken imports, missing environment variables, and components that silently fall back to defaults. Import/export in LangFlow looks trivial on the surface — a JSON file, a button click — but moving flows reliably between environments is a discipline with its own failure modes. This article walks through what actually happens when you export a flow, what breaks during import, and how to build a migration process that doesn't depend on luck.
What a LangFlow Export File Actually Contains
Every flow you build in LangFlow's visual canvas is, underneath, a JSON document. When you click Export, LangFlow serializes the entire flow graph into this JSON structure, and it's worth understanding what's actually in there before you start moving it around.
The export contains:
- Node definitions — every component on your canvas (LLM nodes, prompt templates, retrievers, tool nodes, output parsers) along with their configured parameters
- Edge definitions — the connections between nodes, describing which output feeds which input
- Component metadata — version tags, display names, positions on the canvas (x/y coordinates for the visual layout)
- Field values — the literal values you typed into each component's configuration fields, including things you probably didn't mean to hardcode
- Global variables references — pointers to LangFlow's variable store, which may or may not resolve correctly on the target environment
That last point is where most import problems originate. LangFlow tries to be helpful by separating "secrets" (API keys, tokens) into a global variables system rather than baking them directly into the exported JSON. This is good security practice, but it means an exported flow is never fully self-contained. It's a graph plus a set of external dependencies that must exist on the destination system before the import will behave identically.
A typical export looks something like this at the top level:
{
"name": "customer-support-agent",
"id": "a1b2c3d4-...",
"data": {
"nodes": [...],
"edges": [...],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
},
"description": "",
"last_tested_version": "1.x.x"
}The nodes array is where the real complexity lives — each node carries its own template object with every input field, its current value, and whether that field is exposed as a "tweakable" parameter at runtime.
Exporting a Flow the Right Way
The mechanics of exporting are simple: open the flow, click the Export option in the top-right menu, and LangFlow downloads a .json file named after your flow. But there are a few habits that separate a clean export from one that causes headaches downstream.
First, name your flow deliberately before exporting. LangFlow uses the flow name as the default filename and often as an identifier when re-importing. If you've been iterating with a name like "Untitled Document" or "Copy of Copy of Agent v2," rename it to something that reflects its actual purpose and version before you export. Your future self, staring at a folder of twelve JSON files, will thank you.
Second, check what's hardcoded versus what's a variable reference. Before exporting, open each node that touches an API key, model name, or environment-specific value (bucket names, index names, base URLs) and confirm whether it's using LangFlow's global variables feature or a literal string. If it's a literal string, anyone importing this flow inherits your exact configuration, which is rarely what you want across environments.
Third, export at a stable point, not mid-experiment. If you're actively debugging a broken edge or a node that errors out, fix it first. Exported flows preserve broken states faithfully — LangFlow won't warn you that a component is misconfigured when you export it, it just serializes exactly what's on the canvas.
A command-line-friendly approach, if you're managing this through the LangFlow API rather than clicking through the UI, looks like this:
curl -X GET "http://localhost:7860/api/v1/flows/{flow_id}" \
-H "accept: application/json" \
-H "x-api-key: $LANGFLOW_API_KEY" \
-o exported-flow.jsonThis is the same underlying data the UI export button fetches, just accessible in a form you can script, version, and diff.
Importing Into a New Environment
Importing is where the friction actually shows up. On the destination LangFlow instance, you use the Import option (usually next to Export, or via drag-and-drop onto the flows dashboard) and select your JSON file. LangFlow parses the file and recreates the flow graph — nodes appear in their saved positions, edges reconnect, and configuration values populate.
The problems that surface at this stage generally fall into three buckets.
Missing global variables. If your original flow referenced a global variable called OPENAI_API_KEY or PINECONE_INDEX_NAME, and that variable doesn't exist on the destination instance, the import will still succeed — but the node will show an empty or broken field. LangFlow does not create global variables on your behalf during import. You have to create them manually beforehand, matching the exact names referenced in the flow, or go through each node post-import and re-point the fields.
Component version drift. If the destination LangFlow instance runs a different version than the one that created the export, some components may have changed their input schema. A retriever component that took a top_k integer in version A might expect search_kwargs as a dict in version B. LangFlow generally tries to migrate old node shapes forward, but custom components and recently changed core components are the most likely to break silently — the node imports, but a field is now empty or misaligned, and you won't notice until you run the flow and get a confusing error.
Custom component dependencies. If your flow uses a custom Python component you wrote — say, a custom document loader or a bespoke reranker — that component's code lives on the LangFlow instance, not inside the exported flow JSON. The export only references the component by name and its saved configuration. If the destination instance doesn't have that custom component registered, the import will show a broken or "unknown component" node. You must migrate the custom component code separately, typically by copying the component's Python file into the destination instance's custom components directory before importing the flow.
Here's the general import sequence that avoids most surprises:
- Migrate any custom component code to the destination instance first
- Create all global variables the flow depends on, with correct values for that environment
- Import the flow JSON
- Open every node and visually confirm fields are populated as expected
- Run a test execution before considering the migration complete
Handling Environment-Specific Configuration
The single biggest source of pain in LangFlow migrations is environment-specific configuration bleeding into what should be a portable flow definition. This isn't unique to LangFlow — it's the same problem every "twelve-factor app" discussion has been having for a decade — but LangFlow's visual, node-based nature makes it easy to lose sight of.
The practical fix is to treat every environment-dependent value as a variable, never a literal, from the moment you build the flow. This includes:
- API keys and tokens (OpenAI, Anthropic, Cohere, any provider)
- Vector store connection strings and index/collection names
- Database URLs
- Base URLs for internal services or self-hosted model endpoints
- File paths for local document stores
- Model names, if you expect to swap models between dev and prod (for instance, a cheaper model in dev, a stronger one in prod)
LangFlow's global variables panel lets you define a variable once and reference it from any node's field via the variable picker (usually a small icon next to the input field that toggles between "literal value" and "variable reference"). Get in the habit of using this for anything that isn't genuinely constant across every environment the flow will ever run in.
A useful mental test: if you handed this exported JSON file to a teammate who has never seen your .env file, would the flow still make sense structurally, even if it wouldn't run yet? If yes, you've separated logic from configuration correctly. If the JSON contains your actual production API key in plaintext, you've failed the test, and you now also have a secret-leakage problem sitting in a file that's probably about to get committed to version control.
Version Control for Flows
Because a LangFlow export is just JSON, it's tempting to drop it straight into a git repository and call it done. This mostly works, but a few adjustments make flow version control much more useful in practice.
Pretty-print the JSON before committing so diffs are readable. A minified single-line JSON export produces a diff that's a wall of unreadable text even for a one-field change. Running the export through a formatter first means a reviewer can actually see that you changed a temperature value from 0.2 to 0.7, rather than seeing "1 line changed, +1/-1."
python -m json.tool exported-flow.json > flows/customer-support-agent.jsonAdopt a naming and folder convention early. Something like flows/<environment>/<flow-name>-v<version>.json or simply one folder per flow with the environment handled by variables, not by duplicating the JSON. Duplicating flows per environment (a "prod" copy and a "dev" copy) is a trap — the two copies drift apart silently, and six months later nobody can say which one is authoritative.
Never commit exported flows that contain literal secrets. This is worth a pre-commit hook if your team exports flows regularly — a simple grep for patterns like sk-, AIza, or your internal key prefixes run against any file in a flows/ directory before allowing a commit. It's a small amount of setup that prevents a genuinely bad day.
# .git/hooks/pre-commit (simplified example)
if git diff --cached --name-only | grep -q "flows/.*\.json$"; then
if git diff --cached | grep -qE "sk-[A-Za-z0-9]{20,}"; then
echo "Blocked: possible API key in flow export"
exit 1
fi
fiTag exports with the LangFlow version they were created on. A comment field or a sidecar .meta.json file noting "langflow_version": "1.x.x" saves real time when you're debugging why an old flow doesn't import cleanly into a newer instance.
Automating Migrations with the API
Clicking Export and Import through the UI is fine for one-off moves, but if you're regularly promoting flows from dev to staging to production, or you manage more than a handful of flows, script it. LangFlow exposes a REST API that mirrors everything the UI does, which means the whole export-import cycle can become a repeatable, testable process instead of a manual ritual someone has to remember to do correctly.
A basic promotion script conceptually does three things: fetch the flow from source, optionally rewrite any environment-specific references, and push it to the destination.
#!/usr/bin/env bash
set -euo pipefail
SOURCE_URL="http://dev-langflow.internal:7860"
DEST_URL="http://prod-langflow.internal:7860"
FLOW_ID="a1b2c3d4-e5f6-7890-abcd-ef1234567890"
# 1. Export from source
curl -s -X GET "$SOURCE_URL/api/v1/flows/$FLOW_ID" \
-H "x-api-key: $SOURCE_API_KEY" \
-o /tmp/flow-export.json
# 2. Import into destination
curl -s -X POST "$DEST_URL/api/v1/flows/upload/" \
-H "x-api-key: $DEST_API_KEY" \
-F "file=@/tmp/flow-export.json"This is a starting point, not a finished pipeline. In practice you'll want to add a step that validates the flow imported without broken nodes (LangFlow's API can return the flow's current state, which you can inspect for null or missing required fields), and a step that confirms the destination instance already has the required global variables defined — failing loudly before the import rather than after.
For teams running LangFlow inside CI/CD, this pattern fits naturally into a deployment pipeline: a merge to a flows-staging branch triggers the export/import script against the staging instance, and a merge to main triggers it against production, with the same secret-scanning safeguards from the version control section applied as a pipeline gate.
Common Migration Failures and How to Diagnose Them
A few failure patterns show up repeatedly enough to be worth naming directly, so you recognize them fast instead of re-debugging from scratch each time.
The flow imports but a node shows a red error icon immediately. This is almost always a missing global variable or a custom component that isn't registered on the destination instance. Click into the node — LangFlow usually shows which field is the problem in the node's error state.
The flow runs but produces different output than the source environment. Check for hardcoded values that should have been variables — a model name, a temperature, a system prompt that was tweaked locally after the last export. Diff your JSON against the last known-good version if you have it under version control; this is exactly the scenario version control earns its keep for.
The import silently drops a node or edge. This typically happens with heavily customized components across a version gap, where the destination instance's component registry doesn't recognize a node type at all and LangFlow discards it rather than erroring. Check the destination instance's LangFlow version against the source, and check the custom components directory for anything missing.
Everything imports fine, but the flow fails at the first API call. Nine times out of ten this is an unresolved or empty global variable — the field looked fine because it showed the variable's placeholder name, but the variable itself was never actually created on this instance, so it resolves to nothing at runtime.
The flow references a vector store index or collection that doesn't exist in the new environment. This isn't a LangFlow bug at all — it's a reminder that a flow's success depends on infrastructure LangFlow doesn't manage. Moving a flow to a new environment is only half the job; the vector store, its index, and its ingested documents need to exist there too, and that's a separate migration entirely.
Building a Repeatable Migration Checklist
Once you've hit these failure modes a couple of times, the fix is to stop treating each migration as a one-off and instead follow the same checklist every time. A practical version looks like this:
- Confirm the flow is in a clean, tested state on the source environment before exporting
- Export via API (not just UI click) so the process can be scripted and repeated
- Pretty-print and diff against the last version before committing
- List every global variable the flow references and confirm each exists on the destination with correct values
- List every custom component the flow uses and confirm the code is present on the destination
- Confirm external infrastructure (vector stores, databases, internal APIs) exists and is reachable from the destination
- Import the flow
- Open each node visually and check for red error states or unexpectedly empty fields
- Run at least one full test execution with realistic input before marking the migration complete
- Tag or document the LangFlow version and flow version used, so the next migration starts from a known baseline
None of these steps are individually hard. The value is in doing all of them, every time, instead of the two or three that feel urgent in the moment — which is exactly how "it worked on my machine" becomes "it's broken in production" in a visual workflow tool just as easily as in traditional code.
Where This Fits Into a Broader LangFlow Workflow
Import and export aren't a side feature of LangFlow — they're the mechanism that turns a local prototype into something a team can actually collaborate on and ship. A flow that only ever lives in one person's browser tab isn't really a production asset yet, no matter how well it performs. The moment you need a second environment, a second contributor, or a rollback path, you're relying on exactly the mechanics covered here: clean exports, deliberate handling of secrets and variables, version control that produces readable diffs, and a checklist that catches the failure modes before they reach users.
Treat your exported JSON files the way you'd treat any other infrastructure-as-code artifact — reviewed, versioned, and validated before it moves closer to production. Teams that do this find LangFlow migrations become boring, in the good sense: predictable, scriptable, and no longer dependent on one person remembering which environment variable this flow needs.
If you want to go deeper on building, structuring, and operating LangFlow flows across real environments — not just the drag-and-drop basics — our LangFlow Tutorial course on TeachYou.ai covers this workflow end to end, including hands-on exercises in exporting, importing, and automating flow migrations across dev, staging, and production setups.
BootcampA 30-day guided bootcamp: build, harden and ship a production autonomous agent from scratch.
AI AgentsUnderstand how AI agents really work: the loop, the tools, the memory, and why most agent projects fail.
Related reading