redux-saga

A Redux middleware that models complex async side effects as testable, cancellable sagas using ES6 generators.

Library
npm
v1.5.1
22,418 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
79 /100 Good
Development Activity 68
Maintenance 72
Community 76
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
80 /100 Excellent
Architecture 88
Code Quality 85
Innovation 82
Learning Curve 65

redux-saga is a middleware for Redux that gives asynchronous side effects — data fetching, browser storage access, and other impure operations — a dedicated, testable home outside of your action creators and components. Instead of scattering promises and callbacks through the app, side effects are described as plain JavaScript objects (“effects”) that a generator function yields, and the middleware’s runtime interprets and executes them.

The mental model is that a saga behaves like a separate thread solely responsible for side effects: it can be started, paused, and cancelled using ordinary Redux actions, it can read the full application state, and it can dispatch new actions back into the store. Because sagas are built on ES6 generators rather than promises or async/await, redux-saga gets capabilities that are hard to express with Promise-based approaches alone — most notably cooperative cancellation and declarative effect composition that can be unit-tested by simply asserting on the yielded values, with no mocking of fetch or timers required.

The project is a pnpm-based monorepo split into small, focused packages (@redux-saga/core, @redux-saga/is, @redux-saga/symbols, @redux-saga/deferred, @redux-saga/delay-p, @redux-saga/types, @redux-saga/testing-utils) with the redux-saga npm package itself acting as a thin convenience wrapper that re-exports @redux-saga/core. It has powered production Redux applications for a decade and remains a common answer to “how do I handle non-trivial async flows in Redux” for teams that outgrow thunks.

What You Get

  • A sagaMiddleware factory that mounts onto applyMiddleware and a .run() method to start root sagas against the live store
  • A declarative effects API (call, put, take, takeEvery, takeLatest, fork, spawn, race, all, select, cancel, cancelled) for expressing control flow without hand-rolled promise chains
  • Cooperative task cancellation that propagates down through forked child tasks and cleans up via generator finally blocks
  • Channels (stdChannel, eventChannel, buffered channels) for decoupling saga producers from consumers and modeling event streams
  • A sagaMonitor hook for wiring in devtools/logging that observes every effect triggered, resolved, rejected, or cancelled
  • First-class TypeScript typings (@redux-saga/types) and dedicated testing utilities (@redux-saga/testing-utils) for asserting on yielded effects without mocking network calls

Common Use Cases

  • Fetching data in response to a dispatched action and dispatching success/failure actions back, with built-in support for cancelling an in-flight request when a newer one arrives (takeLatest)
  • Coordinating multi-step async workflows — chained API calls, retries with backoff, polling — as sequential, readable generator code instead of nested promise callbacks
  • Debouncing or throttling user-triggered actions before they reach the network
  • Bridging WebSocket or other push-based event sources into the Redux action stream via eventChannel
  • Testing complex async business logic by asserting on the effects a saga yields, with no need to stub fetch, timers, or the Redux store itself

Under The Hood

Architecture The runtime lives almost entirely in @redux-saga/core, centered on packages/core/src/internal/proc.js, which implements a recursive generator-driving function (proc/next/digestEffect) that steps a saga’s generator forward, dispatches each yielded effect to effectRunnerMap based on its IO symbol tag, and resumes the generator with the effect’s resolved value or thrown error. Task bookkeeping (newTask.js, forkQueue.js, task-status.js) tracks parent/child relationships between forked sagas so that cancelling a parent task recursively cancels its children, and a scheduler.js semaphore batches synchronous re-entrant calls to avoid stack overflows on tight effect loops. middleware.js is a thin adapter that wires this engine into Redux’s applyMiddleware contract, forwarding dispatched actions into a stdChannel that root sagas can take from. This separation — a Redux-agnostic effect interpreter plus a small Redux adapter — is what let the project later split @redux-saga/core’s helper types (is, symbols, deferred, delay-p) into standalone packages other libraries can depend on independently.

Tech Stack The project is a pnpm workspace monorepo built with @preconstruct/cli (via preconstruct build) to produce multiple entry-point bundles per package (ESM, CJS, and a combined UMD build assembled by a custom combine-umd-builds.js script), and versioned/published via Changesets. Source is plain JavaScript with generator syntax, transpiled through Babel (@babel/preset-env, babel-plugin-annotate-pure-calls for tree-shaking hints) rather than TypeScript, while a separate @redux-saga/types package and types/*.test.ts files under packages/core provide and validate the public TypeScript surface. Tests run on Jest with babel-jest; linting uses a flat ESLint config (eslint.config.js) with Husky + lint-staged enforcing checks pre-commit. Runnable examples (counter, shopping cart, real-world) are built with Webpack 4 against a plain react/react-redux stack, illustrating integration rather than shipping as part of the published package.

Code Quality Core behavior is covered by 35+ Jest test files under packages/core/__tests__ (channel semantics, cancellation, the interpreter’s task/fork-queue behavior, scheduler ordering, saga helpers, monitoring hooks), plus a dedicated types/*.test.ts suite that exercises the TypeScript definitions for effects, channels, runSaga, and middleware — an explicit signal the maintainers treat type-level correctness as testable surface, not just documentation. Error handling in the core interpreter is deliberate rather than incidental: sagaError.js tracks which effect crashed to produce actionable stack traces, and proc.js distinguishes cancellation, termination, and thrown-error resumption paths explicitly rather than collapsing them into generic try/catch. Naming is consistent with Redux community conventions (effectRunnerMap, io-helpers, sagaHelpers), and CI plus Husky pre-commit hooks enforce lint and formatting before merge.

What Makes It Unique redux-saga’s defining technical choice is building on ES6 generators instead of async/await or plain Promises, specifically to get cooperative cancellation and effect introspection that Promise-based control flow cannot express cleanly — a yielded effect is just a plain object the runtime can inspect, log, replay, or cancel before it ever executes, which is what makes the library’s assert-on-yielded-effects testing style possible without mocking I/O. The channel abstraction generalizes this beyond simple request/response side effects into a general pub/sub primitive for bridging any external event source into a saga’s take calls, and the fork-queue/task-cancellation model gives structured-concurrency-like guarantees (a cancelled parent reliably cancels all of its descendants) that predates similar guarantees becoming mainstream in other async ecosystems.

Used by 5 apps in this directory

TypeScript
68%
Apache 2.0

Appsmith

Automation · Developer Tools · No Code Platforms

40,959

Open-source low-code platform to build admin panels, dashboards, and internal tools connected to any database or API.

View details
93
Repo Health
79
Technical
66
Dependency
Built with
TypeScript 68%
Java 21%
Updated 1 weeks ago
TypeScript
68%
Apache 2.0

Appsmith

Automation · Developer Tools · No Code Platforms

40,959

Open-source low-code platform to build admin panels, dashboards, and internal tools connected to any database or API.

View details
93
Repo Health
79
Technical
66
Dependency
Built with
TypeScript 68%
Java 21%
Updated 1 weeks ago
TypeScript
68%
Apache 2.0

Appsmith

Automation · Developer Tools · No Code Platforms

40,959

Open-source low-code platform to build admin panels, dashboards, and internal tools connected to any database or API.

View details
93
Repo Health
79
Technical
66
Dependency
Built with
TypeScript 68%
Java 21%
Updated 1 weeks ago
TypeScript
98%
Other

Kibana

Analytics · Monitoring

21,301

Your open source window into the Elastic Stack — query, visualize, and act on data stored in Elasticsearch with real-time dashboards, AI-assisted search, and automated alerting.

View details
98
Repo Health
87
Technical
63
Dependency
Built with
TypeScript 98%
Updated 5 days ago
Go
82%
GPL 3.0

Navidrome

File Storage · Music Audio

23,855

Run your own personal Spotify — stream your entire music collection from any device, anywhere, forever.

View details
91
Repo Health
81
Technical
69
Dependency
Built with
Go 82%
JavaScript 15%
Updated 5 days ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers