LangFlow Memory Nodes: Adding Conversation History to a Flow
Why your LangFlow chatbot forgets everything
You build a flow in LangFlow, connect a Chat Input to a prompt template to an LLM to a Chat Output, and it works beautifully for exactly one message. Ask a follow-up question that depends on what you said earlier — "what about the second one?" or "can you make that shorter?" — and the model responds like it just woke up. It has no idea what "the second one" refers to.
This isn't a bug. It's the default behavior of a stateless request. Every time you call an LLM API, you send a prompt and get a completion back. The model itself holds no memory between calls. Anything that feels like "remembering" in a chat application is really just the previous turns being re-sent as part of the next prompt. If you don't explicitly build that mechanism into your flow, there's nothing there — each message starts from zero.
LangFlow, being a visual wrapper around LangChain-style components, exposes this problem directly instead of hiding it. Which is actually a good thing once you understand it, because it means you can see exactly where conversation history lives, how it's stored, and how it gets injected back into the prompt. This article walks through LangFlow's memory nodes: what they are, how they differ from each other, and how to actually wire one into a working flow so your assistant stops having amnesia after every message.
What "memory" means in a LangFlow context
Before touching any nodes, it helps to separate two things people often conflate: session state and semantic memory.
- Session/conversation memory is the literal transcript of a conversation — user said X, assistant said Y, user said Z. This is what lets a chatbot resolve pronouns, follow up on earlier requests, and maintain a coherent back-and-forth. This is what most people mean when they say "add memory to my flow," and it's the focus of this article.
- Semantic/long-term memory is retrieval over a knowledge base — embeddings stored in a vector database that get searched based on relevance, not recency. That's a RAG pattern, not conversation memory, even though both get called "memory" casually.
LangFlow has components for both, and it's easy to grab the wrong one because the naming overlaps. A "Vector Store" component is not conversation memory. An "Astra DB Chat Memory" or "Message History" component is. If your flow's follow-up questions still fail after adding a memory node, the first thing to check is whether you actually wired in a conversation-history component or accidentally built a document retriever.
This piece is about the former: the components whose entire job is to store and replay the message sequence of a session.
The core building blocks: Memory components in LangFlow
LangFlow ships a handful of components that handle conversation history. The exact list shifts a bit between versions, but the concepts are stable:
- Message History / Chat Memory component. This is the general-purpose node that reads and writes messages tied to a
session_id. It's backed by a storage layer — by default LangFlow's own internal message store (visible in the built-in Playground and message logs), but it can be swapped for external backends. - External store-backed memory components — Redis, Postgres, Astra DB, Zep, and similar integrations. These do the same conceptual job (store messages keyed by session, retrieve them on demand) but persist to a real database instead of LangFlow's local storage, which matters the moment you deploy anywhere beyond your laptop.
- Buffer-style memory — a component that keeps the raw list of past messages and hands them back verbatim, with no summarization or trimming. This is the simplest mental model: literally a list of turns.
- Summarizing/windowed memory — variants that either keep only the last N turns or periodically compress older turns into a running summary via an LLM call. These exist because raw buffers grow without bound and eventually blow your context window.
Underneath, most of this maps directly to LangChain's memory abstractions (ConversationBufferMemory, ConversationSummaryMemory, chat message history classes), because LangFlow is a visual layer on top of that ecosystem. If you've used LangChain in code before, the LangFlow nodes will feel like familiar objects with a drag-and-drop skin.
The important shared property across all of them: every memory component needs a session identifier. Memory in LangFlow is not global — it's scoped per session, so that user A's conversation doesn't bleed into user B's. Get the session ID wiring wrong and you'll either see no memory at all, or worse, see one user's history leaking into another user's chat.
Anatomy of the Message History component
Let's go concrete. The Message History component (the name may appear as "Chat Memory" depending on your LangFlow version) typically exposes these fields:
- Session ID — a string that scopes which conversation this memory belongs to. In the simplest setup this can be left to auto-generate per Playground session. In a real app, you pass in something meaningful, like a user ID or a conversation UUID from your database.
- Order — whether history should be returned oldest-first or newest-first, which matters depending on how your prompt template expects the transcript to read.
- Number of messages / limit — a cap on how many past turns get pulled back, which is your first and cheapest lever against runaway context growth.
- Sender filter — optionally restrict to only user messages, only AI messages, or both.
The component has two jobs depending on where it sits in the graph: it can read stored history to feed into a prompt, and it can write new messages so the next turn has something to read. In LangFlow, this is often handled automatically once the Chat Input and Chat Output nodes are connected properly — they log messages to the store as a side effect — but you should verify this rather than assume it, especially on older component versions where write-back needed to be explicit.
Wiring memory into a basic flow
Here's the standard shape of a memory-aware chat flow in LangFlow:
- Chat Input captures the user's new message.
- Message History component pulls prior turns for the current session.
- A Prompt template combines the system instructions, the retrieved history, and the new user message into one block of text.
- The LLM/Model component (OpenAI, Anthropic, or whichever provider you've configured) receives the full prompt and generates a response.
- Chat Output displays the response and — depending on component version — triggers the write-back of both the user's message and the model's reply into the history store.
The part people get wrong most often is step 3. A memory node retrieving five past turns does nothing useful if your Prompt template doesn't have a variable slot for that history and doesn't place it before the new user message. In the Prompt component, you need an explicit placeholder — something like a {chat_history} variable — sitting inside the template text, with the Message History component's output connected into that variable's input handle. If you only wire the new user message into the prompt and leave history floating unconnected, LangFlow won't error out — it'll just silently ignore it, and you'll be back to the amnesia problem with an extra node in your canvas that isn't doing anything.
A prompt template that actually uses memory typically looks like this in plain text form:
You are a helpful assistant for TeachYouAI's support desk.
Conversation so far:
{chat_history}
New message from user:
{user_input}
Respond concisely and reference earlier context when relevant.Both {chat_history} and {user_input} need to be recognized as template variables inside the Prompt component, each with an incoming connection — history from the Message History node, and the new message from Chat Input.
Session IDs: the detail that silently breaks everything
If there's one section of this article worth re-reading, it's this one. Session ID mismanagement is the single most common reason "I added memory but it's not working."
A few concrete failure modes:
- Hardcoded or default session ID in production. If every user hitting your deployed flow shares the same session ID (because you left the default value in the component instead of parameterizing it), every user sees every other user's conversation history. This is a real data-leakage bug, not just an annoyance.
- New session ID on every request. If your calling application generates a fresh UUID per API call instead of reusing one per conversation, memory will never accumulate — each turn looks like session one, turn one, forever.
- Mismatched IDs between read and write. Some setups accidentally read history under one session key but write new messages under another (for example, if two different Message History nodes in the same flow aren't both wired to the same session variable). The result is a memory store that grows but a flow that never sees it grow.
The fix is almost always the same: expose session_id as a flow-level input (a Tweak, in LangFlow's terminology, or an input passed via the API call), generate it once per real conversation in your calling application, and pass that same value on every subsequent request tied to that conversation. If you're testing in the Playground UI, LangFlow typically manages a session ID for you automatically per browser tab, which is why memory "just works" there but then confuses people once they hit the flow through the API and have to manage it themselves.
Choosing between buffer, windowed, and summary memory
Once basic memory is working, the next decision is which flavor to use, because raw buffer memory has a hard ceiling.
- Buffer memory (keep everything) is the right default for short-lived, low-turn-count interactions — a support widget that resolves in three or four exchanges, a demo, a single-session Q&A tool. It's simple, deterministic, and costs nothing extra to compute. Its failure mode is that on a long conversation, the accumulated history eventually eats your context window and inflates your token bill on every single call, since you're resending the entire transcript each turn.
- Windowed memory (keep only the last N turns) caps that growth by dropping the oldest messages. It's cheap and predictable, but it means older context genuinely disappears — if a user references something from turn two while you're on turn twenty, and your window is set to five, the model has no way to know what they mean.
- Summary memory periodically asks an LLM to compress older turns into a running summary, then feeds that summary plus the recent raw turns into the prompt. This preserves the gist of long conversations without unbounded growth, but it costs an extra LLM call to generate summaries, and summarization is lossy — specific details (exact numbers, exact phrasing the user used) can get smoothed away in the compression step.
For most course-support or documentation-assistant style flows, windowed memory with a reasonably generous limit (say the last 10-15 turns) is a solid practical default: simple to reason about, bounded cost, and rarely loses anything a user actually needed a moment ago. Reach for summary memory only once you've confirmed conversations regularly run long enough that windowing is cutting off references users still care about.
Persistence: local storage versus a real database
By default, a lot of LangFlow experimentation happens against its built-in local message store, which is fine for building and testing but not something you want to depend on in production. It typically lives alongside your LangFlow instance's own data, which means it does not survive a redeploy cleanly, does not scale across multiple server instances, and was never designed to be your application's system of record for chat history.
For anything real, point the memory component at an external store instead — Postgres, Redis, or a dedicated conversational-memory service, depending on what LangFlow version and component set you have available. The tradeoffs are the usual ones:
- Redis is fast and simple for session-scoped data with a TTL, which fits conversation memory well since old sessions naturally age out.
- Postgres gives you durability and lets you query conversation history for analytics or debugging, at the cost of a bit more setup.
- Dedicated memory services (Zep and similar) add features like automatic summarization and entity extraction on top of raw storage, useful once you outgrow "just store the messages."
Whichever you choose, treat the connection credentials the way you'd treat any other secret — pull them from environment variables or your platform's secret manager rather than typing them directly into the component's configuration fields, since flow exports can end up shared or version-controlled.
Debugging a memory node that isn't working
When memory seems broken, work through this checklist before assuming the component itself is faulty:
- Check the session ID is stable across turns. Log or print it if you can. This single check catches the majority of cases.
- Confirm the Prompt template actually references the history variable, and that the variable has an incoming connection from the memory node — not just a text placeholder with nothing wired to it.
- Check read/write direction. Some memory components separate "load history" from "save this turn" into different configuration modes or even different node instances. Make sure both are pointed at the same store and same session key.
- Inspect what's actually being retrieved. Temporarily route the Message History output straight to a Chat Output or a debug node so you can see the raw retrieved messages, rather than trusting that the final LLM response reflects them correctly — a bad prompt template can silently swallow correct history.
- Watch your token counts. If memory is working but responses degrade in quality on long conversations, you may be exceeding a practical context size and need to switch from buffer to windowed or summary memory.
- Verify storage backend connectivity. If you've pointed memory at Redis or Postgres, a silent connection failure can make the component behave as if every session is brand new, since it can't reach the store to read prior turns.
Closing thoughts
Memory in LangFlow isn't magic — it's an explicit, visible mechanism for re-injecting past turns into a stateless LLM call, and once you see it that way, every wiring decision becomes obvious: where the history is stored, how it's keyed by session, how it gets pulled back into the prompt, and how it's trimmed or summarized before the context window fills up. The nodes themselves are simple. The failure modes almost always come from session ID handling or a prompt template that isn't actually connected to the memory output, not from the memory component being broken.
If you want to go deeper — building multi-turn agents, combining conversation memory with retrieval-based memory, and deploying LangFlow flows with a production-grade persistence layer — that's exactly what we cover hands-on in the LangFlow Tutorial course on teachyou.ai, with real flows you can inspect and rebuild yourself.
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