NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #4512 most downloaded on npm
Simple, scalable state management.
Last release 2 days ago
02 Oct 2026
Release timing varies
gaps range from 9 days to 7 months
Nearly every release is documented
notes for 59 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
11 years old
267 releases · first in 2016
4b1c8d3ea2b3de1a2ae852fd5631e33d28a82b15 #4721 Thanks @giaBaoJS ! - fix: assigning length on an observable array now respects intercept . A cancelled
4b1c8d3ea2b3de1a2ae852fd5631e33d28a82b15 #4721 Thanks @giaBaoJS! - fix: assigning length on an observable array now respects intercept. A cancelled or modified splice used to be overridden by a direct write to the backing array, which truncated it without notifying observers and made the next mutation throw "Modification exception". A non-integer length now throws "Out of range" before touching the array.
60be47cab0926d12f22449ec6c809fb5ec6601c4 #4716 Thanks @AcEKaycgR! - fix: observable.box(array) no longer warns under observableRequiresReaction when a spy is active. The create spy event now reports newValue as the value itself rather than a string, matching the declared IBoxDidChange type. Previously the constructor stringified the value, and stringifying an observable array reads its length, which counted as an observable read outside a reactive context. Spy listeners that relied on newValue being a string for create events will now receive the raw value.
3551aeb051ff922717b03c4fbc04a6b98f7f3b3e #4717 Thanks @breken-ai! - Remove the signal abort listener when a reaction disposes itself (r.dispose() or a resolved when), so long-lived AbortSignals no longer accumulate listeners that keep disposed reactions in memory
7e4e27dbfbf0b56770a11e9cba913e5d49c0c6f8 #4718 Thanks @breken-ai! - observe/spy add events of an observable Set now report the value that was actually stored (e.g. the observable copy of a plain object), matching ObservableMap and observable arrays, so set.has(change.newValue) holds
One column per quarter.
105d66d73529812a8eddc0847891e7f0c574e129 #4713 Thanks @xaviergonz ! - perf: reduce memory used by large, mostly unobserved state. intercept / observe
105d66d73529812a8eddc0847891e7f0c574e129 #4713 Thanks @xaviergonz! - perf: reduce memory used by large, mostly unobserved state. intercept / observe handler arrays are allocated at their exact size, an observable's internal observers Set is released once its last observer leaves, observable objects created with the same deep / autoBind options share one default annotation instead of allocating their own, and endBatch() skips the unobservation pass when nothing is pending.7d85a68fb7e449650535aba22e47ce4d21bfbc10 #4592 Thanks @VimHax ! - Extend IReactionDisposer with Disposable
7d85a68fb7e449650535aba22e47ce4d21bfbc10 #4592 Thanks @VimHax! - Extend IReactionDisposer with Disposable
01211a698b64ea94de8e5f276ff8235fcf8ddf96 #4700 Thanks @kubk! - Fix onBecomeObserved not firing for dependencies gained when an observed computed is recomputed inside an action.
6e0a03ef74750b3040c76d3ecc14c4adf202b95a #4710 Thanks @kubk! - Use TypeScript's built-in NoInfer utility instead of a local compatibility alias.
6f002b8e543ca39d3ee23681e28848d7f1724fae #4696 Thanks @gesposito ! - perf: add a node export condition that routes Node and Bun to the existing dist/i
6f002b8e543ca39d3ee23681e28848d7f1724fae #4696 Thanks @gesposito! - perf: add a node export condition that routes Node and Bun to the existing dist/index.js entry, which picks the prebaked development or production CJS build once at require time. importing mobx in Node no longer executes the env-agnostic dist/mobx.mjs with per-call NODE_ENV checks, and mixing import and require in one Node app now yields a single mobx instance.ec1b708026c1578e1c1f6c7bd90be18b26f7ce85 #4695 Thanks @gesposito ! - perf: evaluate NODE_ENV once at module scope in the env-agnostic esm bundles ( di
ec1b708026c1578e1c1f6c7bd90be18b26f7ce85 #4695 Thanks @gesposito! - perf: evaluate NODE_ENV once at module scope in the env-agnostic esm bundles (dist/<pkg>.esm.js and dist/<pkg>.mjs) instead of at every __DEV__ call site. process.env is an exotic object in Node, so each check performed a real environment lookup on hot paths; consumers that execute these files as-is (Node ESM, vitest, SSR) see roughly 10x faster observable writes in dev mode. All env-set artifacts and bundler output are unchanged.
6d8b5fa6c7596d7e5b16e55e3121d81c0c5bb21a #4672 Thanks @chatman-media! - Fix ObservableSet.replace emitting spurious delete/add events (and triggering reactions) for values that are unchanged. It now only fires delete for removed values and add for newly added ones, mirroring ObservableMap.replace.
Note: because replace no longer clears and re-adds every value, the iteration order after replace changes in a (subtle but observable) way. Surviving values now keep their original relative position and newly added values are appended, instead of the whole set being reordered to match the argument. For example, set(["a", "b", "c"]).replace(["d", "b", "a"]) previously iterated as d, b, a, and now iterates as a, b, d. This is arguably the more correct behavior (unchanged values are genuinely unchanged), but if you relied on replace reordering the set to match its argument, you may need to adjust.
9444c624b957b489875e1c6b45deb290034ce4e9 #4694 Thanks @mrpmohiburrahman ! - fix: onBecomeObserved is now called for the dependencies of a computed tha
9444c624b957b489875e1c6b45deb290034ce4e9 #4694 Thanks @mrpmohiburrahman! - fix: onBecomeObserved is now called for the dependencies of a computed that becomes observed while serving a cached value. Previously, observation only cascaded when the newly observed computed also happened to recompute, so an observable with a live observer chain up to a running reaction could still report itself as unobserved and never fire its hook.
53bb83fdf455a4e606bb721ea10040ded7c57796 #4683 Thanks @gesposito! - perf: fast-path primitives in deepEnhancer. Writing a primitive into a deep observable no longer runs the observable/array/plain-object/Map/Set/function type checks; primitives can never be made observable, so they are returned immediately. Creating an observable array of primitives is ~4x faster, and observable Set/Map writes are ~20-25% faster in the perf suite.
030498d6b2bfe4cc27340fed8c706177cb3b28e1 #4684 Thanks @a-y-ibrahim! - Fix a stack overflow ("Maximum call stack size exceeded") that could occur when an onBecomeUnobserved handler disposes a Reaction. Disposing a Reaction re-enters endBatch(), which used to recurse into the same pendingUnobservations drain loop instead of letting the already-running outer loop pick up the newly queued items, causing unbounded stack depth for long enough chains.
a9086076b9ead1a9c933215bffaa9b57d44f6829 #4681 Thanks @spokodev! - Fix ObservableSet union, intersection and symmetricDifference to return results in receiver order, matching native Set, when the argument is a plain Set.
c65a4e14cf48b42cb792dc4c64edbcf56234b32d #4682 Thanks @gesposito! - perf: lazily allocate the internal observers_ Set. Atoms and computed values no longer allocate an empty Set upfront; it is created on first observer instead. Most atoms in large stores are never observed, so this saves roughly 160 bytes per unobserved atom (e.g. ~35% lower heap usage when hydrating 50k instances with 10 observable fields each).
It removes long-deprecated compatibility paths and keeps the React bindings split between mobx-react-lite for function components and mobx-react for c…
1926c69f53168619d688f348aa587e8f3ae579ae #4671 Thanks @kubk! - Release MobX 7, mobx-react-lite 5, and mobx-react 10.
Bundle sizes are down: ESM prod 17.02 KiB gzip -> 13.96 KiB gzip; a minimal tree-shaken example is 10.32 KiB gzip now.
It removes long-deprecated compatibility paths and keeps the React bindings split between mobx-react-lite for function components and mobx-react for class-component support.
MobX 7 is a cleanup release focused on the modern runtime and decorator model.
configure({ useProxies: ... }) is no longer supported.{ proxy: false } options for observable, observable.object, and observable.array are no longer supported.| Removed API | Replacement |
|---|---|
observable.ref |
observableRef |
observable.shallow |
observableShallow |
observable.deep |
observableDeep |
observable.struct |
observableStruct |
computed.struct |
computedStruct |
action.bound |
actionBound |
flow.bound |
flowBound |
comparer.identity |
compareIdentity |
comparer.default |
compareDefault |
comparer.structural |
compareStructural |
comparer.shallow |
compareShallow |
trace API and its related runtime support have been removed. Use toJS, getDependencyTree, getObserverTree, spy or mobx-log package for debugging.mobx-react-lite 5 and mobx-react 10 require MobX 7 and React 18 or later.
mobx-react-lite remains the function-component package. mobx-react remains a thin wrapper around mobx-react-lite that adds class component and Stage 3 @observer class decorator support.
mobx-react-lite if you do not need class component support.mobx-react when you need class components or @observer class decorators.mobx-react-lite supports function components and forwardRef; mobx-react delegates function components to mobx-react-lite and handles classes itself.The recommended public React binding surface for both packages is:
observerObserveruseLocalObservableenableStaticRenderingisUsingStaticRenderingThe following APIs have been removed from the React binding packages:
Provider, inject, and MobXProviderContext; use React.createContext directly.disposeOnUnmount; dispose reactions in componentWillUnmount or return cleanup functions from useEffect.PropTypes; use TypeScript or the regular prop-types package.useObserver; wrap components with observer or use <Observer>.useLocalStore; use useLocalObservable.useAsObservableSource; synchronize values from props into local observable state explicitly.useStaticRendering; use enableStaticRendering.observerBatching, isObserverBatched, batchingForReactDom, batchingOptOut, and batchingForReactNative; remove these imports because React 18+ renderers handle batching.observer(fn, { forwardRef: true }); pass an already-created React.forwardRef(...) component to observer instead.contextTypes handling.979d267d569734dc3cb969ed1880ed68bb79f1b5 #4677 Thanks @kubk! - Shorten minified error URL to reduce production bundle size.`7fd93348e81f484c4ec2dcca8cde5fa6ed7412fe` #4661 Thanks @js2me! - Fix Stage 3 @computed overrides that delegate to a same-named parent getter via supe
7fd93348e81f484c4ec2dcca8cde5fa6ed7412fe #4661 Thanks @js2me! - Fix Stage 3 @computed overrides that delegate to a same-named parent getter via super.
02afa5b6c33441737df81d344161a03bb9aea0c8 #4666 Thanks @kubk! - Remove outdated Flow typechecker support artifacts from the package.
`6b3fb0ee725c0521bbaf7ba901a30261472a0e71` #4639 Thanks @ashishkr96! - feat(mobx): make the 2022.3 @computed decorator lazy. ComputedValue is now crea
6b3fb0ee725c0521bbaf7ba901a30261472a0e71 #4639 Thanks @ashishkr96! - feat(mobx): make the 2022.3 @computed decorator lazy. ComputedValue is now created on first read of the decorated getter rather than eagerly during instance construction, avoiding wasted allocations for getters that are never used. On a 50k-instance × 10-getter class with one read per instance this cuts construction heap by ~50% and construction time by ~25%; the steady-state read path is unchanged. Closes #4616.
f0c68749428fd4d3bba48e9685e44fd1ddbbee76 #4658 Thanks @ashishkr96! - feat(mobx): make the 2022.3 @observable accessor decorator lazy. ObservableValue is now created on first read/write/observe of the decorated accessor rather than eagerly during instance construction, avoiding wasted allocations for fields that are never touched. On a 50k-instance × 10-field class with sparse access (1 of 10 fields read per instance), this cuts construction heap by ~82% and construction time by ~86% versus the eager path. Follow-up to #4639.
7eb54418b16fb9b415c04c5b8e05779790dd74ed #4659 Thanks @kubk! - Fix regression from #4639 where isComputedProp returned false for lazy @computed properties before first read
c22b4b705447a4ccdce93473255f4beb170613f3 #4657 Thanks @kubk! - Add getOrInsert and getOrInsertComputed to ObservableMap for compatibility with ESNext Map typings.
`105c985c71308e439bfeed118fb1ba1eac06824e` #4650 Thanks @kubk! - Avoid Rolldown invalid PURE annotation warnings from Babel-generated optional chainin
105c985c71308e439bfeed118fb1ba1eac06824e #4650 Thanks @kubk! - Avoid Rolldown invalid PURE annotation warnings from Babel-generated optional chaining output.`25e859a3582bcdd3c5a71aa52510adfd924a1a60` #4644 Thanks @kubk! - Fix TypeScript errors when using flow as a standard decorator.
25e859a3582bcdd3c5a71aa52510adfd924a1a60 #4644 Thanks @kubk! - Fix TypeScript errors when using flow as a standard decorator.`52ddce0f179a461b85e578554e35e94bf76edf3c` #4642 Thanks @kubk! - Restore npm release build target forwarding so published tarballs include the standal
52ddce0f179a461b85e578554e35e94bf76edf3c #4642 Thanks @kubk! - Restore npm release build target forwarding so published tarballs include the standalone ESM development and production bundles.`df81c144fb148b64140d761aa61f032a7f429e12` #4523 Thanks @exzos28! - Make FlowCancellationError a proper Error instance while preserving its previous s
df81c144fb148b64140d761aa61f032a7f429e12 #4523 Thanks @exzos28! - Make FlowCancellationError a proper Error instance while preserving its previous string representation.
21fc4de6c09a77caf115aedd2fe6df972637412b #4626 Thanks @kubk! - Export CancellablePromise from the public mobx entrypoint.
`2e703388eda4ba3eefed2bf1f5ca3958980978c3` #4584 Thanks @mweststrate! - Fix #4753: Wrong inferred type of observable.map in TS 5.9+, by @mbest in #578
2e703388eda4ba3eefed2bf1f5ca3958980978c3 #4584 Thanks @mweststrate! - Fix #4753: Wrong inferred type of observable.map in TS 5.9+, by @mbest in #57861d6cf39764f28c6c2e0d2b3912364889739c619 #4563 Thanks @mweststrate! - Fixed memory leak where makeAutoObservable would keep wrapping setters defined on the prototype. Fixes #4553`54e3f71ca02f09b3107290f18d8484b70a6e2f0b` #4528 Thanks @k-g-a! - Fix observable.set not respecting the new value from interceptors
54e3f71ca02f09b3107290f18d8484b70a6e2f0b #4528 Thanks @k-g-a! - Fix observable.set not respecting the new value from interceptors`bca3841347f4fba50ad910e1c4176c56ba0173d1` #3993 Thanks @tonyraoul! - Improve observableset memory footprint and performance
bca3841347f4fba50ad910e1c4176c56ba0173d1 #3993 Thanks @tonyraoul! - Improve observableset memory footprint and performance`4c077738776d5fc7ba0f108805a9ec816c2709b9` #3943 Thanks @tonyraoul! - Fix browser compatability issue introduced in 6.13.4 release
4c077738776d5fc7ba0f108805a9ec816c2709b9 #3943 Thanks @tonyraoul! - Fix browser compatability issue introduced in 6.13.4 release`f91d2e1dc85a53b729c03bd28ab39ffcf0838403` #3935 Thanks @tonyraoul! - Update typescript version to 5.6.2 and added support for esnext iterator helpers
f91d2e1dc85a53b729c03bd28ab39ffcf0838403 #3935 Thanks @tonyraoul! - Update typescript version to 5.6.2 and added support for esnext iterator helpers`a1cf2c63ef92d3d42a5b42a23ff6c7a745664cfd` #3902 Thanks @jzhan-canva! - Fix 2022.3 @action decorators on fields no longer require makeObservable
a1cf2c63ef92d3d42a5b42a23ff6c7a745664cfd #3902 Thanks @jzhan-canva! - Fix 2022.3 @action decorators on fields no longer require makeObservable`f1f922152b45357a49ee6b310e9e0ecf38bd3955` #3921 Thanks @urugator! - fix: #3919 new set methods not working with observable set
f1f922152b45357a49ee6b310e9e0ecf38bd3955 #3921 Thanks @urugator! - fix: #3919 new set methods not working with observable set`5e711e0b4737fd6b5b3c6f9b32afd4f195bc5fc3` #3901 Thanks @peterm-canva! - Shrink Atom and Reaction using a bitfield
5e711e0b4737fd6b5b3c6f9b32afd4f195bc5fc3 #3901 Thanks @peterm-canva! - Shrink Atom and Reaction using a bitfield`16f070e6aac60e9010c2591b1743276d700b23d5` #3898 Thanks @inoyakaigor! - Added new Set methods
16f070e6aac60e9010c2591b1743276d700b23d5 #3898 Thanks @inoyakaigor! - Added new Set methods`ba890343` #3893 Thanks @g6123! - Fix ES6 Map/Set checks for cross-window scripts
`e9e1955f` #3880 Thanks @peterm-canva! - Shrink ComputedValue using a bitfield
e9e1955f #3880 Thanks @peterm-canva! - Shrink ComputedValue using a bitfieldNothing published for this version
`620f78c7` #3812 Thanks @barroij! - Prevent reaction from heeping a Reference to the OldValue that would prevent GC.
`ec5db592` #3792 Thanks @tonyraoul! - Improve observablearray proxy pefromance for es2023.array and es2022.array methods
`c9260974` #3790 Thanks @mweststrate! - Added support for modern 2022.3 Decorators. #3790
c9260974 #3790 Thanks @mweststrate! - Added support for modern 2022.3 Decorators. #3790
Nothing published for this version
`c8d9374d` #3748 Thanks @mweststrate! - Fixed: #3747, computed values becoming stale if the underlying observable was created and updated outside a re
c8d9374d #3748 Thanks @mweststrate! - Fixed: #3747, computed values becoming stale if the underlying observable was created and updated outside a reactive context`3ceeb865` #3732 Thanks @urugator! - - fix: #3728: Observable initialization updates state version.
`bebd5f05` #3727 Thanks @rluvaton! - Added support for signal (AbortSignal) in autorun, reaction and sync when options to dispose them
`4792303e` #3709 Thanks @kubk! - Make trace() noop in production build
`44a2cf42` #3590 Thanks @urugator! - Better support for React 18: Mobx now keeps track of a global state version, which updates with each mutation.
`fed3ff14` #3608 Thanks @emereum! - Do not expose the methods observe_ or intercept_ on computed values and observable values.
`8cf4784f` #3559 Thanks @urugator! - Proxied observable arrays can now safely read/write out of bound indices. See https://github.com/mobxjs/mobx/disc
8cf4784f #3559 Thanks @urugator! - Proxied observable arrays can now safely read/write out of bound indices. See https://github.com/mobxjs/mobx/discussions/3537223e3688 #3551 Thanks @deadbeef84! - Added new option signal to when(), to support abortion using an AbortSignal / AbortController.`b375535c` #3344 Thanks @Nokel81! - Allow readonly tuples as part of IObservableMapInitialValues
`63698d06` #3427 Thanks @RyanCavanaugh! - Apply 'object' constraint where required
63698d06 #3427 Thanks @RyanCavanaugh! - Apply 'object' constraint where required`8e204c7b` #3409 Thanks @Nokel81! - Remove observable.box type inconsistancy
`767baff0` #3338 Thanks @kubk! - Replace any with a generic in Set methods
`2caf7e1a` #3316 Thanks @urugator! - requiresObservable always takes precedence over global reactionRequiresObservable
`d6fa9a19` #3306 Thanks @urugator! - fix missing type inferrence of observe and intercept for arrays
`6b926833` #3287 Thanks @kubk! - Remove any from 'merge' and 'replace' methods of ObservableMap
`23803202` #3273 Thanks @urugator! - fix flow.bound #3271
`654a2013` #3257 Thanks @urugator! - fix: observable map initialization violates enforceActions: "always"
`bf5da6ba` #3239 Thanks @bernardobelchior! - Improved toJS jsdoc
bf5da6ba #3239 Thanks @bernardobelchior! - Improved toJS jsdoc`2d70798e` #3233 Thanks @anderlaw! - eq.ts fix comparer logic
`87e5a037` #3214 Thanks @urugator! - requiresReaction always takes precedence over global computedRequiresReaction
`9d5e65cb` #3193 Thanks @ChocolateLoverRaj! - Make IAtom['reportObserved'] return boolean
9d5e65cb #3193 Thanks @ChocolateLoverRaj! - Make IAtom['reportObserved'] return boolean55508af6 #3189 Thanks @RvanderLaan! - Fix for RangeError in ObservableArray.replace for large arrays`3a7dee6f` #3180 Thanks @kubk! - Fix type inference of observe function
`49468204` #3162 Thanks @upsuper! - Have cancelled when reject with an error rather than a string
`4ac6b454` #3146 Thanks @urugator! - fix #3109: spy: computed shouldn't report update unless the value changed
`0dbf3eb6` #3141 Thanks @urugator! - spy: bound actions report correct object
`d78a1592` #2902 Thanks @z3rog! - chore: observable use internal constants
`4011b378` #2949 Thanks @urugator! - fix #2948: flow ignores autoBind option
`d678ebd7` #2944 Thanks @urugator! - Fix #2941 - flow.bound replaces method on proto with bound function
`bc8db3df` #2779 Thanks @urugator! - In mobx5 all own properties were by default observable regardless of their value. Since mobx6 we treat functional
bc8db3df #2779 Thanks @urugator! - In mobx5 all own properties were by default observable regardless of their value. Since mobx6 we treat functional properties as actions or to be precise autoActions. autoAction provides action's benefits to your functions, without the need to explicitely annotate them as actions.
We think this is useful, but as a consequence, such properties are no longer observable and therefore non-writable and also non-enumerable. This turned out to be suprising and inconvinient to some users:
https://github.com/mobxjs/mobx/discussions/2760
https://github.com/mobxjs/mobx/discussions/2586
https://github.com/mobxjs/mobx/issues/2835
https://github.com/mobxjs/mobx/issues/2629
https://github.com/mobxjs/mobx/issues/2551
https://github.com/mobxjs/mobx/issues/2637
So we decided to change it: All own props including functions are observable (enumerable, writable) as in v5, but additionally all functions that become part of deeply observable structure are by default converted to autoAction/flow.
Note that deep option affects this conversion in the same way as it affects conversion of other values (object/array/map/set).
autoActions/flowsdeep: false ignores all property values (including functions that would be previously converted to autoAction/flow)actions6b324edc #2873 Thanks @urugator! - Fix #2871: toJS throws with configure({ useProxies: "ifavailable" })`ca4914f9` #2836 Thanks @urugator! - Fix #2832 - annotation cache ignores overrides
`5640aa77` #2799 Thanks @urugator! - - fix: user provided debug names are not preserved on production
5640aa77 #2799 Thanks @urugator! - - fix: user provided debug names are not preserved on production
observable(primitive, options) ignores optionsgetDebugName(action) throws [MobX] Cannot obtain atom from undefinedunsafe: trueYour coding agent can read these notes before it upgrades. Set up the MCP server →