By the end of this tutorial, you’ll use _.thru() to run custom transforms inside Lodash chains and replace the pipeline value with your function’s return.
01
Custom step
.thru(fn)
02
Return matters
New chain value.
03
Mid-chain
After map, etc.
04
vs _.tap()
Transform vs observe.
05
Conditional
Branch in fn.
06
Compose helpers
Pipeline stages.
Fundamentals
What Is _.thru()?
_.thru() is Lodash’s custom transform slot inside a chain. Your interceptor receives the current value, and whatever you return becomes the value for the next step. Use it when no single Lodash method fits—inline filtering, reshaping objects, or calling your own helper functions while keeping a fluent pipeline.
💡
Return value drives the chain
Unlike _.tap(), which ignores your return, _.thru()replaces the pipeline value. Always return the data shape the next step expects.
Use _.thru(value, interceptor) standalone, or .thru(interceptor) inside _.chain() / _(value) pipelines. Finish with .value() to unwrap.
A prior step (or the initial wrap) produces the current value passed to your interceptor.
Input
2
Interceptor runs
Your function transforms, filters, validates, or reshapes the value and returns the result.
Transform
3
Return replaces value
Lodash wraps the return value so the next chain method sees the new data.
Replace
=
⚡
Chain continues
More Lodash steps or .value() run on the transformed value—not the pre-thru input.
Important
📝 Notes
_.thru() is for transforms—your interceptor’s return value always drives the next step.
Use _.tap() when you only need to log or observe without changing data.
Prefer built-in methods like filter and map when they express the intent clearly; use thru for custom logic.
Return the data type the next chain step expects—array, object, number, etc.
Stacking multiple .thru() calls is a clean way to compose named pipeline stages.
Next section: Lodash String utilities for text manipulation.
Wrap Up
Conclusion
_.thru() is Lodash’s escape hatch for custom transforms inside fluent chains. Your interceptor’s return becomes the new pipeline value—use it for inline filters, conditional steps, and composing helper functions while keeping code readable.
That completes the core Seq chaining trio: _.chain(), _.tap() for observation, and _.thru() for transformation. Continue with Lodash String methods next.
Return the value explicitly from every thru interceptor
Extract complex thru logic into named functions for readability
Use thru when a single Lodash method cannot express your transform
Pair with .tap() for logging and .thru() for transforming
Validate data shape inside thru when pipelines receive external input
❌ Don’t
Use thru for side effects only—that is what _.tap() is for
Forget to return a value from the interceptor (undefined will break the chain)
Replace clear .filter() calls with thru unless the custom logic is genuinely needed
Return the wrong type for the next chain step without intending a reshape
Nest heavy business logic inside anonymous thru callbacks—name and test helpers instead
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about _.thru()
Use these when adding custom transforms to Lodash chains.
5
Core concepts
🔀01
Custom transform
.thru(fn)
Core
✅02
Return drives chain
New value.
Critical
🔄03
Mid-chain slot
After map, etc.
Pattern
👁️04
vs tap
Transform vs observe.
Compare
🛠️05
Compose helpers
Pipeline stages.
Guideline
❓ Frequently Asked Questions
It calls your interceptor with the current chain value and uses the interceptor's return value as the new value for the next step. It is a custom transform slot inside a Lodash pipeline.
_.tap() runs a side-effect function and keeps the original value. _.thru() replaces the value with whatever your function returns.
When you need a custom inline transform that does not map cleanly to a single Lodash method—conditional filtering, composing helper functions, or reshaping data mid-chain.
Yes. The return value becomes the new wrapped value for subsequent chain steps. Always return the shape the next step expects.
Yes. _.chain(data).map(...).thru(fn).value() is a common pattern—the thru step can return a new array, object, or other value.
Yes. _.thru(value, interceptor) applies the function and returns its result directly, without starting a full chain.
Did you know?
_.thru() is the transform counterpart to _.tap()—together they let you keep pipelines fluent while mixing observation (tap) and custom logic (thru) without breaking out of the chain.