How to Fix 'memory not persisting during development' in CrewAI (TypeScript)
Memory not persisting during development in CrewAI TypeScript usually means your agent state is getting recreated on every run, so the crew starts “fresh” instead of reusing conversation or task context. You’ll see this most often in local dev loops, hot reload, server restarts, or when the memory backend is configured incorrectly.
The error often shows up as one of these symptoms:
- •
memory not persisting during development - •
No memory provider configured - •
MemoryStore is empty after task execution - •
CrewOutput does not include prior context
The Most Common Cause
The #1 cause is recreating the Crew, Agent, or memory store inside a request handler, React component render, or hot-reloaded module. In TypeScript, that means every reload gets a new in-memory instance, so nothing survives between executions.
Broken vs fixed pattern
| Broken pattern | Fixed pattern |
|---|---|
| Memory store created inside the function | Memory store created once and reused |
New Crew on every request | Singleton or shared dependency |
| In-memory backend during dev with HMR | Persistent backend or stable module scope |
// BROKEN: memory resets every time this function runs
import { Crew, Agent, Task } from "@crewai/typescript";
export async function runCrew(input: string) {
const agent = new Agent({
name: "SupportAgent",
role: "Customer support",
goal: "Help users",
});
const crew = new Crew({
agents: [agent],
tasks: [
new Task({
description: input,
agent,
}),
],
memory: {
enabled: true,
type: "in-memory", // lost on refresh/restart
},
});
return await crew.kickoff();
}
// FIXED: create the crew and memory backend once
import { Crew, Agent, Task } from "@crewai/typescript";
import { FileMemoryStore } from "./memory/FileMemoryStore";
const memoryStore = new FileMemoryStore("./.crewai/memory.json");
const agent = new Agent({
name: "SupportAgent",
role: "Customer support",
goal: "Help users",
});
const crew = new Crew({
agents: [agent],
tasks: [],
memory: {
enabled: true,
store: memoryStore,
},
});
export async function runCrew(input: string) {
crew.tasks = [
new Task({
description: input,
agent,
}),
];
return await crew.kickoff();
}
If you’re using Next.js, NestJS, Vite, or any dev server with hot module replacement, module-level initialization still matters. Put shared state outside request handlers and avoid rebuilding it on every invocation.
Other Possible Causes
1. You’re using an ephemeral memory provider
Some setups default to RAM-only storage. That works for tests, but it dies as soon as the process restarts.
// BAD
memory: {
enabled: true,
type: "in-memory",
}
// GOOD
memory: {
enabled: true,
type: "sqlite",
path: "./data/crewai.db",
}
If your app restarts during development, RAM-backed memory will look broken even though it’s behaving correctly.
2. Your environment variables are missing in dev
A lot of teams configure persistence through env vars and forget .env.local or dev-specific overrides.
# .env.example
CREWAI_MEMORY_PROVIDER=sqlite
CREWAI_MEMORY_PATH=./data/crewai.db
const provider = process.env.CREWAI_MEMORY_PROVIDER;
if (!provider) {
throw new Error("No memory provider configured");
}
Check that your local shell actually loads the same values as production.
3. The storage path is invalid or not writable
If your SQLite file or JSON file lives in a directory that doesn’t exist, the memory layer may silently fail or fall back to transient behavior.
import fs from "node:fs";
import path from "node:path";
const dir = path.resolve("./data");
fs.mkdirSync(dir, { recursive: true });
const dbPath = path.join(dir, "crewai.db");
Also verify file permissions if you’re running inside Docker or WSL.
4. You’re creating separate instances per worker/process
If you run multiple Node workers, each process has its own memory unless you use a shared backend.
// BAD for persistence across workers
new Crew({
memory: { enabled: true, type: "in-memory" },
});
Use a shared store:
// GOOD for multi-process dev setups
new Crew({
memory: {
enabled: true,
type: "postgres",
connectionString: process.env.DATABASE_URL!,
},
});
This matters if you use nodemon, PM2 cluster mode, Docker Compose, or a test runner spawning isolated processes.
How to Debug It
- •
Print the active memory config
- •Log the resolved config before
crew.kickoff(). - •Confirm you are not falling back to
in-memory.
- •Log the resolved config before
- •
Check whether the same instance survives between calls
- •Add a module-scoped ID.
- •If it changes on every request, you are recreating the crew.
const instanceId = crypto.randomUUID();
console.log("Crew instance:", instanceId);
- •
Inspect the backing store directly
- •For SQLite/Postgres/JSON files, verify records exist after one run.
- •If nothing is written, your persistence layer is misconfigured.
- •If data exists but isn’t read back, your keying/session logic is wrong.
- •
Disable hot reload temporarily
- •Run the app without HMR.
- •If persistence starts working, your issue is lifecycle-related rather than CrewAI itself.
Prevention
- •Initialize
Crew,Agent, and the memory store at module scope or in a DI container. - •Use a persistent backend in dev (
sqlite,postgres, Redis with persistence) instead of RAM-only storage. - •Add a startup check that fails fast when
CREWAI_MEMORY_PROVIDERor the storage path is missing.
If you want this to behave reliably in TypeScript, treat memory like infrastructure, not like a convenience flag. Once you stop recreating state on every reload and move off ephemeral storage, this error usually disappears immediately.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit