CrewAI Tutorial (TypeScript): building prompt templates for advanced developers
This tutorial shows you how to build reusable prompt templates in CrewAI with TypeScript so your agents produce consistent, structured output instead of drifting on every run. You need this when you want prompts that are versioned, parameterized, and safe to reuse across multiple agents or tasks in a production workflow.
What You'll Need
- •Node.js 18+
- •A TypeScript project with
ts-nodeor a build step - •
crewai - •
dotenv - •An OpenAI API key in
OPENAI_API_KEY - •Basic familiarity with CrewAI agents, tasks, and crews
- •A working
package.jsonwith"type": "module"if you’re using ESM
Install the packages:
npm install crewai dotenv
npm install -D typescript ts-node @types/node
Step-by-Step
- •Start by defining your template as a plain TypeScript function.
Don’t hardcode prompts inside tasks; build a function that accepts variables and returns a string. That gives you one place to enforce structure and keep prompt changes under control.
export type PromptVars = {
role: string;
industry: string;
audience: string;
constraints: string[];
};
export function buildPromptTemplate(vars: PromptVars): string {
return `
You are acting as a ${vars.role} for the ${vars.industry} industry.
Audience:
${vars.audience}
Constraints:
${vars.constraints.map((c) => `- ${c}`).join("\n")}
Output requirements:
- Be specific
- Use bullet points where useful
- Avoid generic advice
`.trim();
}
- •Wire the template into a CrewAI task.
The important part is that the task description is generated from your template before the crew runs. This keeps the agent prompt deterministic and lets you reuse the same template across multiple jobs.
import 'dotenv/config';
import { Agent, Task, Crew, Process } from 'crewai';
import { buildPromptTemplate } from './prompt-template.js';
const analyst = new Agent({
role: 'Senior Banking Analyst',
goal: 'Produce accurate, concise analysis for internal stakeholders',
backstory: 'You write operational analysis for regulated financial services teams.',
});
const task = new Task({
description: buildPromptTemplate({
role: 'senior risk analyst',
industry: 'banking',
audience: 'credit operations managers who need actionable recommendations',
constraints: ['Use plain English', 'Reference compliance implications', 'Keep it under 300 words'],
}),
expectedOutput: 'A structured recommendation memo',
agent: analyst,
});
const crew = new Crew({
agents: [analyst],
tasks: [task],
process: Process.sequential,
});
- •Add variable interpolation for different use cases.
Advanced developers usually need one template that can serve multiple teams. The clean pattern is to keep the shape stable and inject only the variables that change per request.
type UseCase = {
customerType: string;
objective: string;
tone: string;
};
function buildAdvancedTemplate(input: UseCase): string {
return `
Write for ${input.customerType}.
Objective:
${input.objective}
Tone:
${input.tone}
Rules:
- No filler
- Use concrete examples
- If assumptions are needed, state them explicitly
- Return only the final answer
`.trim();
}
const prompt = buildAdvancedTemplate({
customerType: 'insurance claims adjusters',
objective: 'summarize claim triage recommendations from incident notes',
tone: 'direct and operational',
});
- •Run the crew and inspect the output.
At this point you’re testing whether your template actually drives the model toward the format you want. In production, this is where you catch prompt drift before it reaches downstream systems.
async function main() {
const result = await crew.kickoff();
console.log(String(result));
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
- •Make templates testable with snapshot-style assertions.
If you don’t test prompt strings, they will change silently during refactors. Keep the assertion focused on structure, not exact wording unless wording is contractually important.
import assert from 'node:assert/strict';
import { buildPromptTemplate } from './prompt-template.js';
const prompt = buildPromptTemplate({
role: 'fraud analyst',
industry: 'payments',
audience: 'operations leads',
constraints: ['Mention risk signals', 'Do not invent facts'],
});
assert.match(prompt, /fraud analyst/);
assert.match(prompt, /payments/);
assert.match(prompt, /Do not invent facts/);
console.log('Prompt template test passed');
Testing It
Run your script and confirm three things:
- •The generated prompt includes all injected variables.
- •The agent output follows your required structure.
- •Small changes to template variables produce predictable changes in output.
If the model starts ignoring constraints, tighten the template with explicit formatting rules like “Return JSON” or “Use exactly three bullets.” For regulated workflows, store templates in version control and review them like code because they are code.
Next Steps
- •Add Zod validation for prompt variables before building templates.
- •Move templates into separate files per domain, such as banking, insurance, or fraud.
- •Add structured outputs with JSON schema enforcement so downstream services can parse results reliably.
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