🎉  The Alpine Day 2021 videos are out! Watch Now

Persist Plugin

Alpine's Persist plugin allows you to persist Alpine state across page loads.

This is useful for persisting search filters, active tabs, and other features where users will be frustrated if their configuration is reset after refreshing or leaving and revisiting a page.


You can use this plugin by either including it from a <script> tag or installing it via NPM:


You can include the CDN build of this plugin as a <script> tag, just make sure to include it BEFORE Alpine's core JS file.

<!-- Alpine Plugins -->
<script defer src="https://unpkg.com/@alpinejs/[email protected]/dist/cdn.min.js"></script>

<!-- Alpine Core -->
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>


You can install Persist from NPM for use inside your bundle like so:

npm install @alpinejs/persist

Then initialize it from your bundle:

import Alpine from 'alpinejs'
import persist from '@alpinejs/persist'




The primary API for using this plugin is the magic $persist method.

You can wrap any value inside x-data with $persist like below to persist its value across page loads:

<div x-data="{ count: $persist(0) }">
    <button x-on:click="count++">Increment</button>

    <span x-text="count"></span>

In the above example, because we wrapped 0 in $persist(), Alpine will now intercept changes made to count and persist them across page loads.

You can try this for yourself by incrementing the "count" in the above example, then refreshing this page and observing that the "count" maintains its state and isn't reset to "0".

How does it work?

If a value is wrapped in $persist, on initialization Alpine will register it's own watcher for that value. Now everytime that value changes for any reason, Alpine will store the new value in localStorage.

Now when a page is reloaded, Alpine will check localStorage (using the name of the property as the key) for a value. If it finds one, it will set the property value from localStorage immediately.

You can observe this behavior by opening your browser devtool's localStorage viewer:

Chrome devtools showing the localStorage view with count set to 0

You'll observe that by simply visiting this page, Alpine already set the value of "count" in localStorage. You'll also notice it prefixes the property name "count" with "x" as a way of namespacing these values so Alpine doesn't conflict with other tools using localStorage.

Now change the "count" in the following example and observe the changes made by Alpine to localStorage:

<div x-data="{ count: $persist(0) }">
    <button x-on:click="count++">Increment</button>

    <span x-text="count"></span>

Setting a custom key

By default, Alpine uses the property key that $persist(...) is being assigned to ("count" in the above examples).

Consider the scenario where you have multiple Alpine components across pages or even on the same page that all use "count" as the property key.

Alpine will have no way of differentiating between these components.

In these cases, you can set your own custom key for any persisted value using the .as modifier like so:

<div x-data="{ count: $persist(0).as('other-count') }">
    <button x-on:click="count++">Increment</button>

    <span x-text="count"></span>

Now Alpine will store and retrieve the above "count" value using the key "other-count".

Here's a view of Chrome Devtools to see for yourself:

Chrome devtools showing the localStorage view with count set to 0