Skip to content

fix(app-builder): fix SSR hydration mismatch from localStorage#10

Open
falkenbergo wants to merge 1 commit intocursor:mainfrom
falkenbergo:fix/app-builder-ssr-hydration
Open

fix(app-builder): fix SSR hydration mismatch from localStorage#10
falkenbergo wants to merge 1 commit intocursor:mainfrom
falkenbergo:fix/app-builder-ssr-hydration

Conversation

@falkenbergo
Copy link
Copy Markdown

@falkenbergo falkenbergo commented Apr 29, 2026

Summary

Fixes React hydration errors in the app builder when saved chat state exists in localStorage.

Previously, the server rendered the default empty state (createInitialAppState()) while the client immediately read persisted conversations on the first render, so titles, session-derived layout (main classes), and onboarding could disagree between SSR and the client.

Changes

  • Seed initial state only from createInitialAppState() so the first server and client paints match.
  • Restore persisted conversations, active conversation, runtime map, and onboarding (when a valid Cursor API key is saved) in useLayoutEffect after hydration.
  • Rename the loader to readPersistedAppStateFromStorage() (client-only).

Testing

  • Open app builder with existing localStorage data; confirm no hydration warning overlay.
  • Fresh profile / cleared storage still shows default "Project 1" flow.

Note

Low Risk
Behavior change is limited to client-side state initialization timing to prevent SSR hydration warnings; main risk is minor UI flicker/regressions in restore/onboarding state.

Overview
Fixes React hydration mismatches in AppBuilder by bootstrapping initial UI state purely from createInitialAppState() (instead of reading localStorage during initial render).

After hydration, a useLayoutEffect now restores persisted conversations/active conversation and rebuilds runtimeByConversationId, and onboarding is closed when a valid saved Cursor API key is present. The persisted-state loader is renamed/clarified as client-only via readPersistedAppStateFromStorage().

Reviewed by Cursor Bugbot for commit 2298e75. Bugbot is set up for automated code reviews on this repo. Configure here.

…match

Server-rendered HTML used createInitialAppState() while the client read
persisted conversations from localStorage on the first paint, causing
React hydration errors (titles, layout classes). Load saved chat state
and onboarding visibility in useLayoutEffect after mount so server and
client initial trees match.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant