Projects each source value to an Observable (the “inner” Observable) and flattens those inner Observables sequentially. Unlike mergeMap, concatMap waits for each inner Observable to complete before subscribing to the next one, maintaining strict order.
concatMap is equivalent to mergeMap with a concurrency of 1. It ensures that inner Observables are processed one at a time, in order.
A function that returns an Observable that emits values from each projected inner Observable sequentially, waiting for each to complete before moving to the next.
import { from, concatMap, delay } from 'rxjs';interface User { id: number; name: string;}const userIds = [1, 2, 3, 4, 5];// Fetch users one at a time, in orderfrom(userIds).pipe( concatMap(id => fetch(`/api/users/${id}`) .then(res => res.json()) )).subscribe( user => console.log('Fetched:', user), err => console.error('Error:', err), () => console.log('All users fetched'));// Ensures users are fetched in order: 1, then 2, then 3, etc.
Sequential API Requests: When order matters or rate limiting is required
Dependent Operations: When each operation depends on the previous one completing
Database Transactions: Ensure operations execute in order
File Processing: Process files sequentially to avoid conflicts
State Machines: Execute state transitions in strict order
Animation Sequences: Chain animations that must run one after another
If source values arrive faster than inner Observables can complete, concatMap will queue them. This can lead to memory issues with long-running inner Observables and fast sources.
Use concatMap when order is critical. If order doesn’t matter and you want concurrency, use mergeMap. If you want to cancel previous operations, use switchMap.