Persistence

Automatically save and restore your application state across page reloads using browser storage.

Overview

The persistence feature allows your Blazor application to automatically save state to browser storage (LocalStorage or SessionStorage) and restore it when the application reloads. This is perfect for preserving user preferences, shopping carts, form data, and other stateful information.

Key Benefits
  • Automatic save on every state update
  • Automatic restore on application startup
  • Choose between LocalStorage (permanent) and SessionStorage (tab-scoped)
  • Zero boilerplate - just one line of configuration
  • JSON serialization with full type safety
Render Mode Compatibility

LocalStorage persistence works in:

  • ✅ Blazor WebAssembly (full support)
  • ✅ Blazor Auto mode (works after WASM transition)
  • ❌ Blazor Server (LocalStorage not available)

For Blazor Server apps, consider using server-side storage (database, session state, or distributed cache) instead. See the Render Modes guide for more details and alternatives.

Auto-Save to LocalStorage

Enable persistence with a single line in your store configuration. State will be automatically saved to LocalStorage on every update and restored when the application loads.

Program.cs
builder.Services.AddStoreWithUtilities(
    new AppState(),
    (store, sp) => store
        .WithDefaults(sp, "MyApp")
        .WithPersistence(sp, "app-state"));  // Auto-save + restore
That's it!

State is automatically saved on updates and restored on app load. No additional code required.

How It Works

1

Initial Load

When your application starts, the persistence middleware checks if saved state exists in browser storage using the specified key.

2

State Restoration

If saved state is found, it's deserialized and loaded into the store, replacing the initial state. If not found, the initial state is used.

3

Automatic Saving

Every time state is updated via Update(), the new state is automatically serialized to JSON and saved to browser storage.

4

Page Refresh

When users refresh the page or reopen the application, their state is automatically restored, providing a seamless experience.

SessionStorage vs LocalStorage

The library uses LocalStorage by default, but you can configure it to use SessionStorage for tab-scoped persistence.

LocalStorage (Default)

  • Persistence: Data persists across browser sessions
  • Scope: Shared across all tabs and windows
  • Use cases: User preferences, shopping carts, long-term data
  • Cleared when: User manually clears browser data
// Uses LocalStorage (default)
.WithPersistence(sp, "app-state")

SessionStorage

  • Persistence: Data cleared when tab/window closes
  • Scope: Isolated per tab/window
  • Use cases: Form data, temporary state, tab-specific data
  • Cleared when: Tab or window is closed
// Configure for SessionStorage
.WithPersistence(sp, "session-state", useSessionStorage: true)

Configuration Examples

Todo List with Persistence

Program.cs
public record Todo(Guid Id, string Text, bool Completed);

public record TodoState(ImmutableList<Todo> Todos)
{
    public static TodoState Initial => new(ImmutableList<Todo>.Empty);

    public TodoState AddTodo(string text) =>
        this with { Todos = Todos.Add(new Todo(Guid.NewGuid(), text, false)) };
}

// Register with persistence
builder.Services.AddStoreWithUtilities(
    TodoState.Initial,
    (store, sp) => store
        .WithDefaults(sp, "Todos")
        .WithPersistence(sp, "todos"));  // Saves to LocalStorage with key "todos"

Now when users add, toggle, or remove todos, the list is automatically saved. When they reload the page, their todos are restored exactly as they left them.

Shopping Cart Example

Program.cs
public record CartItem(string ProductId, string Name, decimal Price, int Quantity);

public record CartState(ImmutableList<CartItem> Items)
{
    public decimal Total => Items.Sum(i => i.Price * i.Quantity);

    public CartState AddItem(CartItem item) =>
        this with { Items = Items.Add(item) };
}

// Persist cart across sessions
builder.Services.AddStoreWithUtilities(
    new CartState(ImmutableList<CartItem>.Empty),
    (store, sp) => store
        .WithDefaults(sp, "Cart")
        .WithPersistence(sp, "shopping-cart"));

Shopping cart items are preserved even if users close the browser and return days later.

Session-Scoped Form Data

Program.cs
public record FormState(
    string Name,
    string Email,
    string Message,
    bool IsDraft = true);

// Use SessionStorage for temporary form data
builder.Services.AddStoreWithUtilities(
    new FormState("", "", ""),
    (store, sp) => store
        .WithDefaults(sp, "ContactForm")
        .WithPersistence(sp, "contact-form", useSessionStorage: true));

Form data is preserved within the current tab session but cleared when the tab is closed.

Best Practices

Storage Limits

Browser storage typically has a 5-10 MB limit per origin. Avoid persisting large datasets or binary data. Consider persisting only essential state and loading heavy data on demand.

What to Persist

  • User preferences and settings
  • Shopping cart contents
  • Form drafts and work in progress
  • UI state (filters, sorting, pagination)
  • Authentication tokens (with appropriate security)

What NOT to Persist

  • Sensitive data (unless encrypted)
  • Large datasets (use server-side storage)
  • Temporary/transient state
  • Derived/computed values (calculate on load)
  • Binary data or large files

Security Considerations

Important Security Notes
  • LocalStorage/SessionStorage is NOT encrypted by default
  • Data is accessible via JavaScript and browser DevTools
  • Never store passwords, credit cards, or sensitive tokens unencrypted
  • Consider encrypting sensitive data before persistence
  • Use HTTPS to prevent network interception

Clearing Persisted State

You can programmatically clear persisted state when needed (e.g., user logout).

Clearing LocalStorage
@inject IJSRuntime JS

async Task ClearPersistedState()
{
    // Clear specific key
    await JS.InvokeVoidAsync("localStorage.removeItem", "app-state");

    // Or clear all storage
    await JS.InvokeVoidAsync("localStorage.clear");
}
Logout Example
@page "/logout"
@inject IJSRuntime JS
@inject IStore<AuthState> AuthStore

async Task Logout()
{
    // Reset state
    await AuthStore.UpdateAsync(s => AuthState.Initial);

    // Clear persisted data
    await JS.InvokeVoidAsync("localStorage.removeItem", "auth-state");

    // Navigate to login
    NavigationManager.NavigateTo("/login");
}

Troubleshooting

State not persisting?

Ensure .WithPersistence(sp, "storage-key") is called in your store configuration. Check browser DevTools > Application > Local Storage to verify data is being saved.

State not restoring on reload?

Verify the storage key matches between saves and loads. Check browser console for deserialization errors. Ensure your state types are JSON-serializable.

Quota exceeded errors?

Browser storage has size limits (typically 5-10 MB). Reduce the amount of data being persisted or implement data cleanup strategies.

JSON serialization errors?

Ensure all state properties are serializable. Complex types may need custom JSON converters. Avoid circular references.

Next Steps