Skip to main content


When you feel like you're repeating yourself too much or just want to have standard ways to change the value of a superstate, then it's time for extensions!

Let's suppose you have a count superstate:

const count = superstate(0)

Overriding the value of count is very straightforward:


Increasing the value of it is very straightforward as well:

count.set((prev) => prev + 1)

But wouldn't it be magical if you could do the following?:


The example above has a few benefits:

  • It's easier to read,
  • It's easier to write,
  • It's easier to test,
  • It's easier to maintain,
  • It's less verbose,
  • Separates business logic from the implementation.

Creating an extension

From the example above, to create an extension that sums your count:

const count = superstate(0).extend({
sum({ set }, amount: number) {
set((prev) => prev + amount)

count.sum(1) // `` will log 1
count.sum(1) // `` will log 2
count.sum(5) // `` will log 7

Let's understand what's happening here:

sum({ set }, amount: number) {
publish(prev => prev + amount)


is the name of your extension.

{ set }

is a superstate object, which exposes the set method.


The first parameter of an extension should always be reserved to the superstate object.

amount: number

a custom parameter of the .sum() function. This is completely up to us to define and we can have as many parameters as we like. For example:

sum({ set }, x: number, y: number, z: number) {
set(x + y + z)

The ": number" piece is TypeScript. You can omit it when writing vanilla JavaScript.

set(prev => prev + amount)

The regular set function exposed by a superstate object.

Computed values

Given the example below,

const user = superstate({ firstName: 'John', lastName: 'Doe' })

It's exhaustive to always be concatenating the first and last name of the user:

// logs John Doe
console.log(`${} ${}`)

Extensions got you covered by allowing computed values. Let's see how it works:

const user = superstate({ firstName: 'John', lastName: 'Doe' }).extend({

function fullName({ now }) {
const _user = now()

return `${_user.firstName} ${_user.lastName}`

console.log(user.fullName()) // logs John Doe

Just to give you another use-case for computed values:

const money = superstate(100).extend({ formatted })

function formatted({ now, draft }) {
return `$${now()}`

console.log(money.formatted()) // logs $100

Side effects

You can also handle side effects within your extension's scope:

const count = superstate(0).extend({
sum({ set, now }, amount: number) {
const next = now() + amount

// Feel free to do whatever you like.
alert(`count has changed to ${next}.`)

Note that by doing the above, whenever you call .sum(), the alert() will be called as wellโ€”meaning you are the one in charge for managing your side effect(s) lifecycle.