Introduction & Context

Welcome back! You've mastered sequential workflows with prompt chaining and conditional workflows with intelligent routing. Now it's time to unlock dramatic performance improvements by learning parallel processing — executing multiple independent Claude API calls simultaneously instead of waiting for each one to complete.

In this lesson, you'll discover how to transform workflows that take minutes into operations that complete in seconds. You'll learn the difference between synchronous and asynchronous programming, master TypeScript's native async/await patterns, and build a system that asks multiple questions to Claude at the same time.

The Parallelization Workflow Pattern

Before diving into the technical details, let's understand the high-level pattern we'll be implementing. This workflow has two distinct phases that work together to provide both speed and comprehensive results:

Phase 1: Parallel Research Gathering

  • Launch multiple independent Claude API calls simultaneously.
  • Each call researches a different aspect of your topic (attractions, transportation, culture).
  • All questions run concurrently, completing in roughly the time of the slowest individual request.
  • Results are collected and preserved in their original order.

Phase 2: Sequential Result Synthesis

  • Combine all parallel research into a single comprehensive dataset.
  • Send the aggregated information to Claude with instructions for synthesis.
  • Generate a unified, actionable final result (like a complete travel guide).
  • This sequential step ensures all information is properly integrated.

This two-phase approach maximizes both efficiency and quality: you get the speed benefits of parallel processing for data gathering while maintaining coherent analysis through sequential aggregation. It's particularly powerful for research tasks, analysis workflows, and any scenario where you need to quickly gather diverse information and synthesize it into actionable insights.

Understanding Async Operations in TypeScript

When working with the Anthropic API in TypeScript, you use a single unified Anthropic client class. Unlike some other languages, TypeScript doesn't require separate client types for synchronous versus asynchronous operations. Instead, the distinction is made at the method call level using the await keyword.

Every API call to Claude returns a Promise — TypeScript's built-in mechanism for handling asynchronous operations. You can choose to wait for each Promise to complete before moving on (synchronous style), or you can start multiple Promises and let them run concurrently (asynchronous style).

import Anthropic from "@anthropic-ai/sdk";

// Initialize the Anthropic client (works for both sync and async operations)
const client = new Anthropic();

// Synchronous approach - each call waits for the previous one to finish
const response1 = await client.messages.create(...);  // Wait for this to complete
const response2 = await client.messages.create(...);  // Then wait for this to complete

In contrast, when you want to run multiple operations in parallel, you start them without immediately awaiting them, then use Promise.all() to wait for all of them to complete:

// Asynchronous approach - all calls can run simultaneously
const promise1 = client.messages.create(...);  // Start this
const promise2 = client.messages.create(...);  // Start this too
const [response1, response2] = await Promise.all([promise1, promise2]);  // Wait for both

In summary:

  • Use sequential await calls for simple workflows where each step depends on the previous one.
  • Use Promise.all() when you want to launch multiple independent Claude API calls at once, dramatically improving performance for batch or parallel tasks.

Choosing the right approach is the key to optimizing your Claude workflows for both simplicity and speed.

Async/Await Fundamentals for Claude Workflows

TypeScript has built-in support for asynchronous programming through Promises and the async/await syntax. Unlike some languages that require external libraries, TypeScript's async model is native to the language and works seamlessly with the Anthropic SDK.

The async keyword transforms a regular function into one that returns a Promise, while await pauses execution until a Promise resolves. This makes asynchronous code read like synchronous code while maintaining the performance benefits of non-blocking operations:

import Anthropic from "@anthropic-ai/sdk";

// Initialize the Anthropic client
const client = new Anthropic();

async function yourAsyncFunction(question: string): Promise<string> {
    // The 'await' allows other operations to run while waiting for the API response
    const response = await client.messages.create({
        model: "claude-sonnet-4-6",
        max_tokens: 2000,
        messages: [{ role: "user", content: question }]
    });
    
    const textBlock = response.content.find(block => block.type === "text");
    if (!textBlock || textBlock.type !== "text") {
        throw new Error("No text response");
    }
    
    return textBlock.text;
}

This approach is particularly effective for I/O-bound operations like API calls, where much of the time is spent waiting for network responses. TypeScript's runtime automatically manages the event loop, allowing your code to handle multiple concurrent operations efficiently.

Running Async Code

To execute async functions in TypeScript, you simply call them. Since async functions return Promises, you need to use await when calling them from another async context:

async function main() {
    // Call your async function and await the result
    const result = await yourAsyncFunction("What are the top 3 must-see attractions in Paris?");
    console.log(result);
}

// Run the async main function
main();

This pattern of wrapping your async code in a main() function is a common approach for organizing async programs. TypeScript handles all the Promise management automatically, making it simple to work with asynchronous operations.

Concurrent Execution with Promise.all()

The real power of async programming comes from running multiple operations concurrently. Promise.all() starts multiple Promises simultaneously and waits for all of them to complete, returning results in the original order:

async function main() {
    // Start all operations concurrently (these begin executing immediately)
    const tasks = [
        yourAsyncFunction("What are the top attractions in Paris?"),
        yourAsyncFunction("How do I get around Paris?"), 
        yourAsyncFunction("What are French cultural norms?")
    ];
    
    // Wait for all tasks to complete
    // Note: Results are returned in the same order as the original tasks
    const results = await Promise.all(tasks);
    
    console.log(results);
}

main();

The key insight: while one API call waits for Claude's response, the runtime can initiate or continue processing other API calls. This transforms sequential waiting time into concurrent execution time.

Creating Async Functions for Claude Calls

Now that you understand the fundamentals, let's build the foundation of our parallel workflow by creating an async function specifically designed for Claude API calls. This function will handle individual questions while being optimized for concurrent execution.

import Anthropic from "@anthropic-ai/sdk";

// Initialize the Anthropic client
const client = new Anthropic();

async function askQuestion(question: string): Promise<[string, string]> {
    /**
     * Async function to ask Claude a single question
     */
    console.log(`🔄 Asking: ${question}`);
    
    // Send async request to Claude with system prompt
    const response = await client.messages.create({
        model: "claude-sonnet-4-6",
        max_tokens: 2000,
        system: "You are a travel expert. Give brief, helpful answers.",
        messages: [{ role: "user", content: question }]
    });
    
    // Extract the answer with type checking
    const textBlock = response.content.find(block => block.type === "text");
    if (!textBlock || textBlock.type !== "text") {
        throw new Error(`No text response for question: ${question}`);
    }
    const answer = textBlock.text;
    
    console.log(`✅ Answered: ${question}`);
    
    return [question, answer];
}

The console.log statements help visualize when each question starts and completes, while returning a tuple of [question, answer] makes it easy to match responses back to their original questions when processing parallel results. The system prompt ensures consistent, focused responses from Claude. Note the type annotation : Promise<[string, string]>, which indicates this function returns a Promise that resolves to a tuple of two strings.

Preparing the List of Questions

With our async function ready, let's define the independent research questions that will form the parallel component of our workflow. Parallel processing shines when you have independent problems that don't rely on each other's answers:

// List of independent questions for Paris trip planning
const questions = [
    "What are the top 3 must-see attractions in Paris?",
    "What is the most efficient way to get around Paris as a tourist?",
    "What are important cultural etiquette tips for visitors to France?"
];

These questions cover different aspects of travel planning (attractions, transportation, culture) and are completely independent of each other, making them perfect candidates for parallel execution.

Building Parallel Task Collections

Now let's put Promise.all() to work by creating multiple tasks that execute simultaneously. This is where the parallel magic happens:

async function main() {
    /**
     * Execute parallel research and create comprehensive travel plan
     */
    console.log(`Starting ${questions.length} research questions in parallel...`);
    
    // Execute all tasks in parallel
    const results = await Promise.all(
        questions.map(question => askQuestion(question))
    );
    
    console.log("\nResearch completed!");
}

The .map() method creates an array of Promises representing work to be done, while Promise.all() starts all Promises simultaneously and returns results in the original order regardless of completion sequence. Each result is a tuple containing the question and its corresponding answer.

Aggregating Results for Final Analysis
Running the Complete Parallel Workflow

Let's bring it all together into a complete workflow that demonstrates the full power of parallel processing followed by intelligent aggregation:

async function main() {
    /**
     * Execute parallel research and create comprehensive travel plan
     */
    console.log(`Starting ${questions.length} research questions in parallel...`);
    
    // Execute all tasks in parallel
    const results = await Promise.all(
        questions.map(question => askQuestion(question))
    );
    
    console.log("\nResearch completed!");
    
    // Aggregate results into final travel plan
    const travelPlan = await createTravelPlan(results);
    
    console.log("\nParis Travel Guide:");
    console.log(travelPlan);
}

// Run the parallel workflow
main();

When you run this workflow, you'll see the power of parallel execution unfold in three distinct stages:

  1. Instant Launch: All three "🔄 Asking" messages appear immediately as the API calls fire off simultaneously.
  2. Concurrent Completion: The "✅ Answered" messages arrive as Claude finishes each response — often in a different order than they were asked, proving your requests are truly running in parallel.
  3. Intelligent Synthesis: All this concurrent research gets woven together into a comprehensive travel guide that combines the speed benefits of parallel processing with thoughtful analysis.

This visual progression clearly demonstrates how your requests execute concurrently rather than waiting for each other, transforming what could be a slow sequential process into a fast, efficient workflow that delivers both speed and quality.

Starting 3 research questions in parallel...
🔄 Asking: What are the top 3 must-see attractions in Paris?
🔄 Asking: What is the most efficient way to get around Paris as a tourist?
🔄 Asking: What are important cultural etiquette tips for visitors to France?
✅ Answered: What are the top 3 must-see attractions in Paris?
✅ Answered: What are important cultural etiquette tips for visitors to France?
✅ Answered: What is the most efficient way to get around Paris as a tourist?

Research completed!

Paris Travel Guide:
# Quick Paris Travel Guide

## Must-See Attractions
1. **Eiffel Tower** - Best at night when illuminated; book observation deck tickets in advance
2. **Louvre Museum** - Home to Mona Lisa; pre-book timed entry tickets to skip lines
3. **Notre-Dame Cathedral** - Currently under restoration but exterior still impressive; explore Île de la Cité area

## Getting Around
**Use the Metro** - fastest and cheapest option
- Get a day pass for 3+ trips per day
- Download Citymapper app for directions
- Most attractions are 30 minutes away max
- Walk between nearby sites (Louvre to Notre-Dame area)

## Essential Etiquette
**Greetings:** Always say "Bonjour" when entering shops/restaurants
**Dining:** Don't modify menu items; tip 5-10%
**Dress:** More formal than typical tourist wear
**Language:** Learn basic French phrases - locals appreciate effort

## Practical Tips
- Shops close 12-2 PM for lunch and Sundays
- Speak quietly in public
- Book restaurant reservations in advance
- Carry your own shopping bag

**Best times to visit:** Spring (April-June) or fall (September-November) for mild weather and fewer crowds.
Performance Benefits and Use Cases

This two-stage approach provides significant performance benefits while maintaining result quality. The parallel research phase completes in roughly the time of the slowest individual question, while the aggregation phase ensures all information is properly synthesized into a usable travel plan.

This pattern works well for any scenario where you need to:

  • Research multiple independent topics quickly
  • Aggregate diverse information into a unified result
  • Balance speed with comprehensive analysis

The performance benefits are most significant when you have many independent research topics or when individual API calls have high latency.

Summary & Practice Preparation

You've mastered parallel processing patterns that transform slow sequential workflows into lightning-fast concurrent operations. The combination of parallel research gathering and sequential result synthesis provides both speed and quality, making it ideal for complex analysis tasks like travel planning, market research, or technical evaluations.

In the upcoming exercises, you'll apply these patterns to real-world scenarios and learn to handle the nuances of concurrent Claude workflows. Remember: use parallel processing for independent research tasks, then aggregate results sequentially for comprehensive final analysis.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal