Tips for maximising Jazz performance

Use the best crypto implementation for your platform

The fastest implementations are (in order):

  1. Node-API crypto (only available in some Node/Deno environments) or RNQuickCrypto on React Native
  2. WASM crypto
  3. JavaScript fallback (slowest, but most compatible)

Check whether your environment supports Node-API. Some edge runtimes may not enable WASM by default.

Minimise group extensions

Group extensions make it easy to cascade permissions and they’re fast enough for most cases. However, performance can slow down when many parent groups need to load in the dependency chain. To avoid this, create and reuse groups manually when their permissions stay the same for both CoValues over time.

Note: Implicit CoValue creation extends groups automatically. Be careful about how you create nested CoValues if you are likely to build long dependency chains.

const SubSubItem = co.map({
  name: z.string()
});
const SubItem = co.map({
  subSubItem: SubSubItem
});
const Item = co.map({
  subItem: SubItem
});

// Implicit CoValue creation
// Results in Group extension for subItem and subSubItem's owners.
const item = Item.create({
  subItem: {
    subSubItem: {
      name: "Example"
    }
  }
});

// Explicit CoValue creation
// Does not result in Group extension.
const fasterItem = Item.create({
  subItem: SubItem.create({
    subSubItem: SubSubItem.create({
      name: "Example"
    })
  })
})

// Alternative
const subSubItem = SubSubItem.create({ name: "Example"});
const subItem = SubItem.create({ subSubItem: subSubItem });
const fasterItem = Item.create({ subItem: subItem });

Choose simple datatypes where possible

CoValues will always be slightly slower to load than their primitive counterparts. For most cases, this is negligible.

In data-heavy apps where lots of data has to be loaded at the same time, you can choose to trade off some of the flexibility of CoValues for speed by opting for primitive data types.

z.string() vs CoTexts

In case you use a CoText, Jazz will enable character-by-character collaboration possibilities for you. However, in many cases, users do not expect to be able to collaborate on the text itself, and are happy with replacing the whole string at once, especially shorter strings. In this case, you could use a z.string() for better performance.

Examples:

  • names
  • URLs
  • phone numbers

z.object()/z.tuple() vs CoMaps

CoMaps allow granular updates to objects based on individual keys. If you expect your whole object to be updated at once, you could consider using the z.object() or z.tuple() type. Note that if you use these methods, you must replace the whole value if you choose to update it.

Examples:

  • locations/co-ordinates
  • data coming from external sources
  • data which is rarely changed after it is created
const Sprite = co.map({
  position: z.object({ x: z.number(), y: z.number() }),
});

const Location = co.map({
  position: z.tuple([z.number(), z.number()]),
});

const mySprite = Sprite.create({ position: { x: 10, y: 10 }});
mySprite.$jazz.set("position", { x: 20, y: 20 }); 
// You cannot update 'x' and 'y' independently, only replace the whole object

const myLocation = Location.create({ position: [26.052, -80.209] });
myLocation.$jazz.set("position", [-33.868, -63.987]) 
// Note: you cannot replace a single array element, only replace the whole tuple