CrewAI Tutorial (TypeScript): adding memory to agents for intermediate developers
This tutorial shows you how to give CrewAI agents persistent memory in TypeScript so they can remember prior interactions across tasks and runs. You need this when your agent must keep context about a customer, a case, or a workflow instead of treating every request like a blank slate.
What You'll Need
- •Node.js 18+ installed
- •A TypeScript project initialized with
npm init -y - •CrewAI JS/TS packages installed
- •An OpenAI API key set in your environment
- •A
.envfile or shell access for environment variables - •Basic familiarity with CrewAI agents, tasks, and crews
Install the packages first:
npm install @crewai/core @crewai/memory dotenv
npm install -D typescript tsx @types/node
Step-by-Step
- •Create a minimal TypeScript project setup and load your API key.
CrewAI memory needs a working runtime and credentials. Keep the config simple so you can focus on the memory layer first.
// src/config.ts
import "dotenv/config";
export const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
if (!OPENAI_API_KEY) {
throw new Error("OPENAI_API_KEY is missing");
}
- •Define a persistent memory store for your crew.
For an intermediate setup, use file-backed storage so memory survives process restarts. This is enough to prove the pattern before moving to Redis or a database.
// src/memory.ts
import { Memory } from "@crewai/memory";
export const memory = new Memory({
storage: {
type: "sqlite",
path: "./crewai-memory.sqlite",
},
});
- •Create an agent that reads from and writes to memory.
The important part is attaching the same memory instance to the agent configuration. That gives the agent access to prior context when it responds.
// src/agent.ts
import { Agent } from "@crewai/core";
import { memory } from "./memory";
export const supportAgent = new Agent({
name: "Support Agent",
role: "Customer support assistant",
goal: "Help customers while remembering relevant prior context",
backstory: "You handle repeat customer requests and must stay consistent.",
memory,
});
- •Add tasks that benefit from remembered context.
Use one task to capture facts and another to reuse them later. In real systems, this maps cleanly to intake, enrichment, and follow-up workflows.
// src/tasks.ts
import { Task } from "@crewai/core";
import { supportAgent } from "./agent";
export const collectCustomerTask = new Task({
description: "Ask for the customer's preferred contact method and issue summary.",
expectedOutput: "A short structured customer profile.",
agent: supportAgent,
});
export const followUpTask = new Task({
description: "Continue the conversation using any remembered customer details.",
expectedOutput: "A helpful follow-up response referencing earlier context.",
agent: supportAgent,
});
- •Run two consecutive crew executions with shared memory.
The second run should be able to retrieve facts stored during the first run. This is where you verify that memory is actually persistent, not just in-process state.
// src/index.ts
import { Crew } from "@crewai/core";
import { collectCustomerTask, followUpTask } from "./tasks";
import { supportAgent } from "./agent";
async function main() {
const crew = new Crew({
agents: [supportAgent],
tasks: [collectCustomerTask],
});
const firstResult = await crew.kickoff({
inputs: {
customerName: "Jordan",
issue: "Card payment failed twice",
preferredContactMethod: "email",
},
});
console.log("First run:", firstResult);
const followUpCrew = new Crew({
agents: [supportAgent],
tasks: [followUpTask],
});
const secondResult = await followUpCrew.kickoff({
inputs: {
question: "What contact method did Jordan prefer?",
},
});
console.log("Second run:", secondResult);
}
main().catch(console.error);
- •Add a quick smoke test for persistence across restarts.
Kill the process, rerun it, and confirm the second execution still has access to prior data. If it does, your SQLite-backed memory is working as intended.
{
"scripts": {
"dev": "tsx src/index.ts",
"build": "tsc --noEmit"
}
}
Testing It
Run npm run dev once and watch the first task store useful customer details. Then stop the process and run it again; if memory is persistent, the agent should still reference earlier context instead of guessing.
If the second output ignores prior facts, check three things first:
- •The same
memoryinstance is attached to the agent each time. - •The SQLite file exists at
./crewai-memory.sqlite. - •Your prompts are specific enough to ask for remembered data.
For production-style validation, test with two separate Node processes and different inputs for different users. You want to confirm isolation per conversation or per case ID before you put this behind an API.
Next Steps
- •Move from SQLite to Redis or Postgres-backed storage for multi-instance deployments.
- •Add conversation keys so each customer or case gets isolated memory.
- •Combine memory with retrieval tools so agents can pull policy docs or case notes alongside chat history
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