Skip to content

Persist extention hydration #343

Closed

Description

@noveogroup-amorgunov

Hi! First of all, thank you for releasing the new version of the library.
I have two questions about how to properly use the persist extension.

Schema example
import { Collection } from '@msw/data'
import { persist } from '@msw/data/extensions/persist'
import { sync } from '@msw/data/extensions/sync'
import { z } from 'zod'

const userSchema = z.object({
  id: z.number(),
  email: z.email(),
  password: z.string(),
})

const wishlistSchema = z.object({
  id: z.number(),
  get user() {
    return userSchema
  },
  productIds: z.array(z.number()),
})

export async function createDb() {
  const users = new Collection({
    schema: userSchema,
    extensions: [
      persist(),
      sync(),
    ],
  })
  
  const wishlists = new Collection({
    schema: wishlistSchema,
    extensions: [persist(), sync()],
  })
  
  wishlists.defineRelations(({ one }) => ({
    user: one(users),
  }))

  return {
    users,
    wishlists,
  }
}

////

createDb().then(
  db => startDatabaseMigration(db)
)

 1 – Asynchronous hydration

If I call a function to seed fixtures from the global scope, queries against the collections always return empty results, since the data is hydrated asynchronously.

export async function startDatabaseMigration() {
  const users = db.users.findMany(q => q.where({ id: value => Boolean(value) }))

  // users is always an empty array

To work around this, I can add a small delay — but this isn’t obvious from the docs and feels a bit hacky (it might also break logic that expects the collections to be ready synchronously):

export async function startDatabaseMigration() {
+  await new Promise(resolve => setTimeout(resolve, 10))

  const users = db.users.findMany(q => q.where({ id: value => Boolean(value) }))

  // users is correctly restored from localStorage

Is this the correct approach to handle the issue, or am I misusing the extension?

2 – Hydrating related entities

When I am trying to hydrate a related entity, I get an error saying that the user entity doesn’t exist yet at the time of hydration:

collection-BJduKbwC-….js?v=aa5ed28a:2330 Uncaught (in promise) OperationError$1: Failed to create a new record with initial values: does not match the schema. Please see the schema validation errors above.
    at async Promise.all (:5174/index 0)
await in create		
(anonymous)	@	db.ts:28

With errors like this:

Image

What I’ve discovered is that when closing the browser tab, the user inside wishlists record is not saved. So during the next hydration, the errors above occur:

Image

You can see in the screenshot that there’s no user field.

Here’s how I create the entities:

  const user = await db.users.create({ ...userData, id: generateId('user') })
  await wait(10)

  await db.wishlists.create({
    id: generateId('wishlist'),
    user,
    productIds: [3, 4, 5, 6, 7],
  })

On the first run (without reloading the page), everything works correctly:

Image

Is this a bug, or am I doing something wrong?

If needed, I can create a CodePen reproduction for both issues.

Activity

  1. kettanaito commented on Aug 30, 2026

    @kettanaito
    Member

    Thanks for reporting this, @noveogroup-amorgunov.

    There were multiple issues tangled here, all fixed and will be released in the next version. Hydration of relational records has been fixed at its core (genuine bug), but what concerns async hydration, I've refactored Data to enforce sync hydration so you don't have to await anything. One side effect of that is your schemas must be sync now, too.

    In next major versions, I'll likely migrate all Collection operations to be async, thus unlocking async schemas.

  2. kettanaito commented on Aug 30, 2026

    @kettanaito
    Member

    Released: v1.1.8 🎉

    This has been released in v1.1.8.

    Get these changes by running the following command:

    npm i @msw/data@latest
    

    Predictable release automation by Release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions