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
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
One column per quarter.
Fixed ObservableSet.prototype.forEach not being reactive in 4.x #2341 by @melnikov-s
Fixed ObservableSet.prototype.forEach not being reactive in 4.x #2341 by @melnikov-s
Add error when computed value declared for unspecified getter #1867 by @berrunder
Fixed #2326 correct array is passed to callbacks by @urugator
Fixed #2278, map.delete should respect strict mode, by @urugator
Fixed #2253, #1980, map key order not always preserved by @urugator
Fixed #2412, non-enumerable getters not being picked up by extendObservable by @urugator
Several performance improvements
Dropped browser fields from package.json
Fix process.env replacement in build #2267 by @fredyc
Define action name to be as the function name #2262 by @nadavkaner
Fixed #2230 computedvalue: throw error object instead of string when options is empty #2243 by @ramkumarvenkat
extendObservable: can be used existing properties again. Fixes #2250 through #2252 by @davefeuchtMake initial values of observable set accept readonly array #2202
_allowStateReadsStart & _allowStateReadsEnd. This is low level stuff you shouldn't need that's mostly useful for library creators. #2233observableRequiresReaction and updating observable during reaction #2195action #2213 (see detailed explanation)Nothing published for this version
Fixed a possible issue with action stack errors and multiple mobx versions installed at the same time #2135.
Added experimental reactionRequiresObservable & observableRequiresReaction config #2079, Docs
Don't use global and self keywords unless defined. Fixes #2070.
global and self keywords unless defined. Fixes #2070._startAction and _endAction to be able to start and action and finish it without needing a code block. This is low level stuff you shouldn't need that's mostly useful for library creators.Fixed potential memory leak in observable maps, when non-primitive values are used as keys. Fixes #2031 through #2032.
Added computedConfigurable config #2011, #2013
…was an oversight in 4.10.0). Apologies for the breaking change (lack of new major version numbers). If lock files are properly used however, no harm s…
BREAKING CHANGE
Reverted the support of Symbols in general in MobX 4, as it gives to many potential build errors and increases the system requirements for MobX 4 (which was an oversight in 4.10.0). Apologies for the breaking change (lack of new major version numbers). If lock files are properly used however, no harm should be caused by this change.
Added support for symbol named properties in maps and objects. Fixes #1809 and #1925 through #1944 by @loklaan
set support for observable.set, see #1945 by xaviergonzAllow symbol keys in ObservableMap, see #1930 by pimterry
Fixed observable.set compatibility with IE 11, see #1917 by kalmi
Fixed regression #1878, accidental use of Symbol breaking Internet Explorer / React Native compatibility.
Symbol breaking Internet Explorer / React Native compatibility.Fixed regression in toJS: observable maps were not properly serialized. Fixes #1875
toJS: observable maps were not properly serialized. Fixes #1875Introduced support for observable sets! Through #1592 by @newraina
Features
observable.box now accepts an equals option, to be able to pass a custom comparision function. Through #1862, #1874 by @fi3ework. Fixes #1580Fixes
flow, see #1827 by @xaviergonztrace(true) not being able to handle multi-line comments in traced function. Fixes #1850@computed now introduces non-configurable properties, to fail fast on incorrect inheritance or property deletion. Fixes #1867enforceActions and isolateGlobalState now work correctly when used together. Fixes #1869MobX now requires TypeScript 3 (this was already the case in 5.7.0, but in this version the difference is actually noticeable in the typings).
flow in TypeScript 3. Fixes #1816 through #1825 by ismailhabibIGNORE_MOBX_MINIFIY_WARNING=true to skip the built-in minification warning. See #1835 by fi3eworkUpgraded typings to TypeScript 3
@computed on a React component. The MobX 5 behavior here has been reverted to the MobX 4 behavior.keepAlive has become smarter and won't recomputed computed values that are kept alive, as long as they aren't read. Implements #1534
Fixed bug in toJS not handling null values correctly. Fixes #1557 through #1783 by @wangyiz4262
toJS not handling null values correctly. Fixes #1557 through #1783 by @wangyiz4262toJS now has a recurseEverything everything option, that even detects and converts observable objects that are "behind" non-observable objects. See #1
toJS now has a recurseEverything everything option, that even detects and converts observable objects that are "behind" non-observable objects. See #1699 by wangyiz4262comparer, see #1751 by pdong(Minor version of 5 was bumped significantly to make the number better correlate together :-))
(Minor version of 5 was bumped significantly to make the number better correlate together :-))
extendObservable in a class constructor caused errors to be throwndelete-ing a property was not always picked up by the reactivity systemremove()-ing a property was not always picked up by the has() and get() utilitieshas now returns true for computed fieldsget now returns a value for computed fields_allowStateChangeInsideComputed. Don't use it :-).Fixed #1650, decorating fields with the name toString does not behave correctly.
toString does not behave correctly.Improved typings of decorate, see #1711 by makepost
Improved handling of multiple MobX instances. MobX will no longer complain about being loaded multiple times (one should still prevent it though, to p
configure({ isolateGlobalState: true }). Note that this means that observables from the different MobX instances won't cooperate. Fixes #1681, #1082enforceActions options now supports the values: "never", "observed" and "always" to make the behavior more clear. Fixes #1680, #1473Nothing published for this version
Fixed #1534: @computed({keepAlive: true}) no long calculates before being accessed.
$mobx export symbol for MobX 5 forward compatibityIntroduced the entries(observable) API, by @samjacobclift through #1536
entries(observable) API, by @samjacobclift through #1536@computed({ set: ... }) wasn't picked upFixed flow typings for mobx.configure #1521 by @andrew--r
mobx.configure #1521 by @andrew--rmobx.flow, fixes #1527@observable in combination with a getter. #1511 by @quanganhtrantoJS now uses Map internally, for faster detection of cycles. #1517 by @loathebobserve hooks not being triggered when using mobx.set, Fixed in #1514 by @quanganhtranUndeprecated ObservableMap, fixes #1496
configure({ enforceActions: "strict" }), which is more strict then enforceActions: true, as it will also throw on non-observed changes to observables. See also #1473reaction where not properly picked up by the global reaction systemObservableMap, fixes #1496Symbol.toStringTag (if available / polyfilled). This allows libraries like Ramda to detect automatically that observable arrays are arrays. Fixes #1490. Note that Array.isArray will keep returning false for the entire MobX 4 range.configurable and writable, like in MobX 3. Fixes #1477fail, by @mtaran-google through #1483 and #1482Import default from MobX will no longer throw, but only warn instead. This fixes some issues with tools that reflect on the default export of a module
default from MobX will no longer throw, but only warn instead. This fixes some issues with tools that reflect on the default export of a modulerunInAction overload in the flow typings. #1451 by AMilassindecorate. See #1450 by makepostIntroduced keepAlive as option to computed
keepAlive as option to computedany for their generic argumentsflow cancellationwhen is now automatically an action.@computed properties are now declared on their owner rather then the protoptype. Fixes an issue where @computed fields didn't work in React Native on proxied objects. See #1396action and action.bound decorated fields are now reassignable, so that they can be stubbedFixed issue where exceptions like TypeError: Cannot define property:__mobxDidRunLazyInitializers, object is not extensible. were thrown. Fixes #1404
Nothing published for this version
Updated flow typings, see #1393 by andrew--r
The options struct and compareStructural for computed values are deprecated, use @computed.struct or computed({ equals: comparer.structural}) instead.
This is the extensive list of all changes.
The changes mentioned here are discussed in detail in the release highlights, or were simply updated in the docs.
MobX 4 introduces separation between the production and non production build. The production build strips most typechecks, resulting in a faster and smaller build. Make sure to substitute process.env.NODE_ENV = "production" in your build process! If you are using MobX in a react project, you most probably already have set this up. Otherwise, the idea is explained here.
Introduced flow to create a chain of async actions. This is the same function as asyncActions of the mobx-utils package
These flow's are now cancellable, by calling .cancel() on the returned promise, which will throw a cancellation exception into the generator function.
flow also has experimental support for async iterators (async * function)
Introduced decorate(thing, decorators) to decorate classes or object without needing decorator syntax.
Introduced onBecomeObserved and onBecomeUnobserved. These API's enable hooking into the observability system and get notified about when an observable starts / stops becoming used. This is great to automaticaly fetch data from external resources, or stop doing so.
computed / @computed now accepts a requiresReaction option. If it set, the computed value will throw an exception if it is being read while not being tracked by some reaction.
To make requiresReaction the default, use mobx.configure({ computedRequiresReaction: true })
Introduced mobx.configure({ disableErrorBoundaries }), for easier debugging of exceptoins. By NaridaL through #1262
toJS now accepts the options: { detectCycles?: boolean, exportMapsAsObjects?: boolean }, both true by default
Observable maps are now backed by real ES6 Maps. This means that any value can be used as key now, not just strings and numbers.
The flow typings have been updated. Since this is a manual effort, there can be mistakes, so feel free to PR!
computed(fn, options?) / @computed(options) get fn() now accept the following options:
set: (value) => void to set a custom setter on the computed propertyname: "debug name"equals: fn the equality value to use for the computed to determine whether its output has changed. The default is comparer.default. Alternatives are comparer.structural, comparer.identity or just your own comparison function.requiresReaction: boolean see above.autorun(fn, options?) now accepts the following options:
delay: number debounce the autorun with the given amount of milliseconds. This replaces the MobX 3 api autorunAsyncname: "debug name"scheduler: function a custom scheduler to run the autorun. For example to connect running the autorun to requestAnimationFrame. See the docs for more detailsonError. A custom error handler to be notified when an autorun throws an exception.reaction(expr, effect, options?) now accepts the following options:
delay: number debounce the autorun with the given amount of milliseconds. This replaces the MobX 3 api autorunAsyncfireImmediately. Immediately fire the effect function after the first evaluation of exprequals. Custom equality function to determine whether the expr function differed from its previous result, and hence should fire effect. Accepts the same options as the equals option of computed.autorun acceptswhen(predicate, effect?, options?) now accepts the following options:
name: "debug name"onError. A custom error handler to be notified when an autorun throws an exception.timeout: number a timeout in milliseconds, after which the onError handler will be triggered to signal the condition not being met within a certain timeThe effect parameter of when has become optional. If it is omitted, when will return a promise. This makes it easy to await a condition, for example: await when(() => user.profile.loaded). The returned promise can be cancelled using promise.cancel()
There is now an utility API that enables manipulating observable maps, objects and arrays with the same api. These api's are fully reactive, which means that even new property declarations can be detected by mobx if set is used to add them, and values or keys to iterate them.
values(thing) returns all values in the collection as arraykeys(thing) returns all keys in the collection as arrayset(thing, key, value) or set(thing, { key: value }) Updates the given collection with the provided key / value pair(s).remove(thing, key) removes the specified child from the collection. For arrays splicing is used.has(thing, key) returns true if the collection has the specified observable property.get(thing, key) returns the chlid under the specified key.observable, observable.array, observable.object, observable.map and extendObservable now accept an additional options object, which can specify the following attributes:
name: "debug name"deep: boolean. true by default, indicates whether the children of this collection are automatically converted into observables as well.defaultDecorator: <decorator> specifies the default decorator used for new children / properties, by default: observable.deep, but could be changed to observable.ref, observable.struct etc. (The deep property is just a short-hand for switching between observable.deep or observable.ref as default decorator for new properties)The changes mentioned here are discussed in detail in the migration notes
Map to be globally available. Polyfill it if targeting IE < 11 or other older browsers.Map and several Symbols to exist for its typings. So make sure that the lib configuration of your project is set to "es6". (The compilation target can still be "es5")observable.shallowArray(values) has been removed, instead use observable.array(values, { deep: false })observable.shallowMap(values) has been removed, instead use observable.map(values, { deep: false })observable.shallowObject(values) has been removed, instead use observable.object(values, {}, { deep: false })extendShallowObservable(target, props), instead use extendObservable(target, props, {}, { deep: false })observable.ref, observable.shallow, observable.deep, observable.struct can no longer be used as functions. Instead, they should be passed as part of the decorators param to resp. observable.object and extendObservableextendObservable is extendObservable(target, props, decorators?, options?). This also means it is no longer possible to pass multiple bags of properties to extendObservable. extendObservable can no longer be used to re-declare properties. Use set instead to update existing properties (or introduce new ones).map.values(), map.entries(), map.keys(), map[@@iterator]() and array[@@iterator]() no longer return an array, but an iterator. Use mobx.values(map) or Array.from(map) to convert the iterators to arrays.@computed.equals, instead, you can now use @computed({ equals: ... })useStrict(boolean) was dropped, use configure({ enforceActions: boolean }) insteadisolateGlobalState was dropped, use configure({ isolateGlobalState: true}) insteadshareGlobalState feature. Instead, projects should be setup properly and it is up to the hosting package to make sure that there is only one MobX instanceexpr has been moved to mobx-utils. Remember, expr(fn) is just computed(fn).get()createTransformer has been moved to mobx-utilscontext explicitly to autorun, reaction etc is no longer supported. Use arrow functions or function.bind instead.autorunAsync. Use the delay option of autorun instead.autorun, when, reaction don't support name as first argument anymore, instead pass the name option.extras. namespace has been dropped to enable tree-shaking non-used MobX features. All methods that where there originally are now exported at top level. If they are part of the official public API (you are encouraged to use them) they are exported as is. If they are experimental or somehow internal (you are discouraged to use them), they are prefixed with _.spyReportStart, spyReportEnd, spyReport and isSpyEnabled are no longer public. It is no longer possible to emit custom spy events as to avoid confusing in listeners what the possible set of events is.isStrictModeEnabledobservable(value) will only succeed if it can turn the value into an observable data structure (a Map, Array or observable object). But it will no longer create an observable box for other values to avoid confusion. Call observable.box(value) explictly in such cases.isComputed and isObservable no longer accept a property as second argument. Instead use isComputedProp and isObservableProp.whyRun, use trace insteadAtom class is no longer exposed. Use createAtom instead (same signature).struct and compareStructural for computed values are deprecated, use @computed.struct or computed({ equals: comparer.structural}) instead.isModifierDescriptor is no longer exposed.deepEqual is no longer exposed, use comparer.structural instead.setReactionScheduler -> configure({ reactionScheduler: fn })reserveArrayBuffer -> configure({ reactionErrorHandler: fn })ObservableMap is no longer exposed as constructor, use observable.map or isObservableMap insteadmap -> observable.maprunInAction no longer accepts a custom scopedefault export that made it harder to tree-shake mobx. Make sure to always use import { x } from "mobx" and not import mobx from "mobx".asFlat etc. If you war still using this, see the MobX 2 -> 3 migration notes..move methodobservable.deep.struct modifierobservable.ref.struct modifierobservable.struct now behaves like observable.ref.struct (this used to be observable.deep.struct). That is; values in an observable.struct field will be stored as is, but structural comparison will be used when assigning a new valueonError option of reactions insteadThe issues are incoprorated in the above notes.
observable apionBecomeObserved & onBecomeUnobservedonError handler when creating reactionsobserveMap as backend implementation of observable mapsNothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Fixed accidental dependency on the node typings. Fixes #1387 / #1362
Fixed #1358: Deep comparison failing on IE11. By le0nik through #1359
Fixed #1118, the deepEquals operator build into mobx gave wrong results for non-primitive objects. This affected for example computed.struct, or the c
computed.struct, or the compareStructural of reactionNothing published for this version
Republished 3.4.0, because the package update doesn't seem to distibute consistently through yarn / npm
Improve Flow support by exposing typings regularly. Flow will automatically include them now. In your .flowconfig will have to remove the import in th
Fixed regression bug where observable map contents could not be replaced using another observable map #1258
Fix bug where custom comparers could be invoked with undefined values. Fixes #1208
undefined values. Fixes #1208map.replace would trigger reactions for unchanged values, fixes #1243NaN was considered unequal to NaN when a deep compare was made #1249Fixed #1139 properly: transaction is no longer deprecated and doesn't disable tracking properties anymore
Undeprecated transaction, see #1139
transaction, see #1139@action on a getter #971Your coding agent can read these notes before it upgrades. Set up the MCP server →