How to persist svelte store

You can manually create a subscription to your store and persist the changes to localStorage and also use the potential value in localStorage as default value.

Example

<script>
  import { writable } from "svelte/store";
  const store = writable(localStorage.getItem("store") || "");

  store.subscribe(val => localStorage.setItem("store", val));
</script>

<input bind:value={$store} />

For Svelte Kit I had issues with SSR. This was my solution based on the Svelte Kit FAQ, the answer by Matyanson and the answer by Adnan Y.

As a bonus this solution also updates the writable if the localStorage changes (e.g. in a different tab). So this solution works across tabs. See the Window: storage event

Put this into a typescript file e.g. $lib/store.ts:

import { browser } from '$app/env';
import type { Writable } from 'svelte/store';
import { writable, get } from 'svelte/store'

const storage = <T>(key: string, initValue: T): Writable<T> => {
    const store = writable(initValue);
    if (!browser) return store;

    const storedValueStr = localStorage.getItem(key);
    if (storedValueStr != null) store.set(JSON.parse(storedValueStr));

    store.subscribe((val) => {
        if ([null, undefined].includes(val)) {
            localStorage.removeItem(key)
        } else {
            localStorage.setItem(key, JSON.stringify(val))
        }
    })

    window.addEventListener('storage', () => {
        const storedValueStr = localStorage.getItem(key);
        if (storedValueStr == null) return;

        const localValue: T = JSON.parse(storedValueStr)
        if (localValue !== get(store)) store.set(localValue);
    });

    return store;
}

export default storage

This can be used like this:

import storage from '$lib/store'

interface Auth {
    jwt: string
}

export const auth = storage<Auth>("auth", { jwt: "" })

From https://github.com/higsch/higsch.me/blob/master/content/post/2019-06-21-svelte-local-storage.md by Matthias Stahl:

Say we have a store variable called count.

// store.js
import { writable } from 'svelte/store';

export const count = writable(0);

// App.svelte
import { count } from 'store.js';

In order to make the store persistent, just include the function useLocalStorage to the store object.

// store.js
import { writable } from 'svelte/store';

const createWritableStore = (key, startValue) => {
  const { subscribe, set } = writable(startValue);
  
  return {
    subscribe,
    set,
    useLocalStorage: () => {
      const json = localStorage.getItem(key);
      if (json) {
        set(JSON.parse(json));
      }
      
      subscribe(current => {
        localStorage.setItem(key, JSON.stringify(current));
      });
    }
  };
}

export const count = createWritableStore('count', 0);

// App.svelte
import { count } from 'store.js';

count.useLocalStorage();

Then, in your App.svelte just invoke the useLocalStorage function to enable the persistent state.

This worked perfectly for me in Routify. For Sapper, JHeth suggests "just place count.useLocalStorage() in onMount or if (process.browser) in the component consuming the store. "