Repository navigation
Persist extention hydration #343
Description
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 arrayTo 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 localStorageIs 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:
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:
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:
Is this a bug, or am I doing something wrong?
If needed, I can create a CodePen reproduction for both issues.
Activity
kettanaito commentedon Aug 30, 2026
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.
kettanaito commentedon Aug 30, 2026
Released: v1.1.8 🎉
This has been released in v1.1.8.
Get these changes by running the following command:
Predictable release automation by Release.
refactor: migrate from forked @mswjs/data to @msw/data v1.1.8 (#42)