What monads really are (and why you’ve been using them all along)

If you’ve ever chained .then() calls, mapped over an array, or used async/await, congratulations, you’ve already used a monad. You just didn’t call it that.

Most explanations start with abstract math: endofunctors, morphisms, category theory. Let’s sk…


This content originally appeared on DEV Community and was authored by John Munn

If you’ve ever chained .then() calls, mapped over an array, or used async/await, congratulations, you’ve already used a monad. You just didn’t call it that.

Most explanations start with abstract math: endofunctors, morphisms, category theory. Let’s skip that.

A monad is a pattern for sequencing transformations safely, a way to handle “and then…” without breaking everything when something goes wrong.

With tools like effect-ts gaining traction and Rust patterns bleeding into JS, understanding monads is becoming less academic and more practical.

The everyday monad: promises

Let’s start with something you already know.

const getUser = (id) =>
  fetch(`/api/users/${id}`).then(res => res.json());

getUser("123")
  .then(user => fetch(`/api/orders/${user.id}`))
  .then(res => res.json())
  .then(console.log);

Each .then() takes the output of the previous step, keeps it wrapped in a Promise, and passes it forward. That’s a monad in the wild. A container that lets you chain work without tearing it open each time.

Why we bother

Without monads, you’d constantly be doing this:

getUser("123")
  .then(userPromise =>
    userPromise
      ? // What if user is null?
        fetch(`/api/orders/${userPromise.id}`).then(res => res.json())
      : Promise.reject("no user") // What if address is missing?
  );

That’s messy and fragile. Monads abstract the wrapping and unwrapping so you can focus on the logic, not the plumbing.

Here’s a clearer before-and-after view:

// Nested promises
fetch(url)
  .then(r => r.json())
  .then(data => data?.user?.address ? data.user.address : null);

// Monadic chain (conceptually)
fetch(url)
  .then(r => r.json())
  .then(Maybe.of)
  .flatMap(u => Maybe.of(u.user))
  .flatMap(u => Maybe.of(u.address));

The key insight: flatMap lets you chain functions that return wrapped values, while map is for functions that return plain ones.

Build one: the "Maybe" monad

Sometimes you get data that might be null or undefined. Instead of endless if checks, we’ll make a simple Maybe wrapper.

In plain JavaScript:

const Some = (value) => ({ kind: "some", value });
const None = () => ({ kind: "none" });

const map = (m, fn) =>
  m.kind === "some" ? Some(fn(m.value)) : None();

const flatMap = (m, fn) =>
  m.kind === "some" ? fn(m.value) : None();

Usage:

const safeDivide = (a, b) => (b === 0 ? None() : Some(a / b));

const result = flatMap(safeDivide(10, 2), x => safeDivide(x, 5));
console.log(result); // { kind: "some", value: 1 }

Add TypeScript for safety

Once this pattern clicks, TypeScript can enforce these contracts at compile time instead of runtime.

type Maybe<T> = { kind: "some"; value: T } | { kind: "none" };

const Some = <T>(value: T): Maybe<T> => ({ kind: "some", value });
const None = <T>(): Maybe<T> => ({ kind: "none" });

const flatMap = <T, U>(m: Maybe<T>, fn: (v: T) => Maybe<U>): Maybe<U> =>
  m.kind === "some" ? fn(m.value) : None();

TypeScript now stops you from mapping the wrong function or unwrapping a None() by accident.

Why this matters in real projects

You already use monads every day:

  • Promise<T> for async results
  • Array<T> for multiple results
  • Option/Maybe<T> for optional values
  • Result<T, E> (inspired by Rust) for success or failure

They give you consistency, the same predictable way to chain transformations without blowing up your code.

Real-world example:* parsing a nested API response safely.

const getCity = (res: any): Maybe<string> =>
  res && res.user && res.user.address ? Some(res.user.address.city) : None();

Some(response)
  .flatMap(r => getCity(r))
  .map(city => city.toUpperCase());

// Returns None() and short-circuits safely
Some(null).flatMap(r => getCity(r)).map(city => city.toUpperCase());

When simple is better

Sometimes you don’t need monads at all. If a null check does the job, do that. Use monads when data needs to flow through several uncertain steps or when you’re composing transformations across async boundaries.

When to reach for them

  • Error handling: Replace scattered try/catch with a Result monad
  • Optional data: Use Maybe instead of if (x) checks
  • Async logic: You’re already doing it with Promise
  • Complex data flows: Compose transformations safely instead of nesting callbacks

Takeaways

  • A monad is just a wrapper + a way to chain (flatMap)
  • You use them already: promises, arrays, optionals
  • TypeScript helps you express them safely, but you can learn the idea in JS first
  • Once you start seeing them, you’ll notice where they simplify your code, and where they’re overkill

The next time you write if (x && x.y && x.y.z), ask yourself. Am I just building a monad by hand?

What's next

Explore these for deeper dives:


This content originally appeared on DEV Community and was authored by John Munn


Print Share Comment Cite Upload Translate Updates
APA

John Munn | Sciencx (2025-11-05T16:40:03+00:00) What monads really are (and why you’ve been using them all along). Retrieved from https://www.scien.cx/2025/11/05/what-monads-really-are-and-why-youve-been-using-them-all-along-2/

MLA
" » What monads really are (and why you’ve been using them all along)." John Munn | Sciencx - Wednesday November 5, 2025, https://www.scien.cx/2025/11/05/what-monads-really-are-and-why-youve-been-using-them-all-along-2/
HARVARD
John Munn | Sciencx Wednesday November 5, 2025 » What monads really are (and why you’ve been using them all along)., viewed ,<https://www.scien.cx/2025/11/05/what-monads-really-are-and-why-youve-been-using-them-all-along-2/>
VANCOUVER
John Munn | Sciencx - » What monads really are (and why you’ve been using them all along). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/11/05/what-monads-really-are-and-why-youve-been-using-them-all-along-2/
CHICAGO
" » What monads really are (and why you’ve been using them all along)." John Munn | Sciencx - Accessed . https://www.scien.cx/2025/11/05/what-monads-really-are-and-why-youve-been-using-them-all-along-2/
IEEE
" » What monads really are (and why you’ve been using them all along)." John Munn | Sciencx [Online]. Available: https://www.scien.cx/2025/11/05/what-monads-really-are-and-why-youve-been-using-them-all-along-2/. [Accessed: ]
rf:citation
» What monads really are (and why you’ve been using them all along) | John Munn | Sciencx | https://www.scien.cx/2025/11/05/what-monads-really-are-and-why-youve-been-using-them-all-along-2/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.