Dash applications often require sharing data between callbacks without rerunning expensive computations or relying on an external database. This is where dcc.Store
comes in to store your app data on the client side.
In this tutorial, we’ll explore what dcc.Store
is, how it works, and best practices for using it effectively in Dash applications.
What is dcc.Store
, and why do we need it?
A bit of history
Initially, people used to store data for Dash apps in hidden HTML components. However, that wasn’t an ideal solution: there was no way to retain data after reloading the page or closing the tab, and embedding large amounts of data in HTML could bloat the app and cause serious slowdowns.
As a result, the Plotly team introduced dcc.Store
in Dash 0.32, and it has become one of the most essential components.
Introduction to dcc.Store
The dcc.Store
component serves multiple important functions: it enables data sharing between callbacks without repeatedly passing large objects, stores intermediate calculation results to prevent costly recomputations, and can maintain data persistence during page reloads or multi-page navigation—when configured with the appropriate storage type.
It has four key properties:
id
: Like any other regular Dash component, this is used for callbacks.storage_type
: Eithermemory
,session
, orlocal
(more on this below).data
: The initial value for the store when the app loads.modified_timestamp
: The latest modification timestamp.
You can create as many dcc.Store
components as you need and include them in your app’s layout. Here’s an example:
from dash import Dash, dcc, html, Input, Output, State
app = Dash(__name__)
app.layout = html.Div([
html.H1("My app"),
# ... other components
# Memory stores examples
dcc.Store("user_id_store", storage_type="memory"),
dcc.Store("dashboard_option_store", storage_type="local", data=False),
])
# A callback example
@app.callback(
Output("user_id_store", "data"),
Input("button_login", "n_clicks"),
)
def login_callback(n_clicks):
if n_clicks:
# ... get user_id from login form
return user_id
# Another callback example with user_id as state
@app.callback(
Output("dashboard_option_store", "data"),
Input("dashboard_option_dropdown", "value"),
State("user_id_store", "data"),
)
def dashboard_option_callback(dashboard_option, user_id):
if user_id:
# ... get dashboard option for this specific user_id
return dashboard_option
In this example, we set up a user_id_store
component to keep the current user ID. That information can then be passed as state to many callbacks requiring knowledge of which user is performing a particular action, such as selecting a dashboard option.
Why it is needed
Dash operates as a stateless framework, meaning each callback function operates independently—processing requests and discarding user-specific data afterward. This architecture makes global variables ineffective for data persistence across callback executions (you should never use global variables in Dash apps!).
The dcc.Store
component provides client-side storage for JSON-serializable data directly in the user’s browser, making it easy to retain and share data across multiple interactions (i.e., callbacks). It is perfect for storing IDs, or small size data.

dcc.Store
) and database data retrieval and processing.However, if you want to maintain access to larger data between interactions (i.e. callbacks), you will need alternative storage methods like an external database (Redis, SQLite, PostgreSQL, MongoDB) because stored data on the clientside would require transmitting it over the network every time, which could be a huge bottleneck.
Learn best practices for callbacks here: Dash callbacks best practices (with examples)
Understanding dcc.Store
Storage Types
A key feature of dcc.Store
is its flexibility in how data is stored. It offers three different storage types, each with unique characteristics:
# Three different ways to initialize a store
dcc.Store(id='memory-store', storage_type='memory') # Default
dcc.Store(id='session-store', storage_type='session')
dcc.Store(id='local-store', storage_type='local')
Each storage type serves different purposes:
- Memory (
storage_type='memory'
): Data persists only for the current page session. If the user refreshes the page, the data is lost. This is the default and is best for temporary data that can be regenerated easily. - Session (
storage_type='session'
): Data persists across page refreshes within the same browser tab but is cleared when that tab (or the browser) is closed. This uses the browser’ssessionStorage
API. - Local (
storage_type='local'
): Data persists indefinitely, even after the browser is closed and reopened. This uses the browser’slocalStorage
API and is great for user preferences or application settings.
Your choice depends on your specific requirements. For instance, use local
for user preferences that should persist across sessions, session
for data that should survive a refresh but not a browser restart, and memory
for transient data like intermediate computational results.
Pro-tip: It can be helpful to add a suffix like -store
or _memory
to all your dcc.Store
IDs. This makes it easy to identify which inputs and outputs are stores in your callbacks.
How much can you store?
The amount of data that can be stored in dcc.Store
depends on the selected storage_type
:
- Memory: Limited only by the browser’s available memory but cleared on page refresh.
- Session and Local: These rely on the browser’s
sessionStorage
andlocalStorage
APIs, which typically allow up to 10MB per domain (source). However, this limit varies between browsers and may be smaller on mobile devices.
Additionally, performance considerations matter when using dcc.Store
for large datasets. Each time a callback accesses or updates dcc.Store
, Dash serializes and transmits the data over the network. If you store large JSON objects (for example, a DataFrame of thousands of rows), it can lead to significant bandwidth usage and slow performance, especially for users with limited internet speeds. In such cases, consider using server-side caching or database storage instead.
How to debug dcc.Store
Depending on the storage type, you can inspect, update, or delete storage values, which can be useful during development, especially for session
and local
types.
For this example, I will use a To-Do app built in Dash. You can find how I created it in this tutorial: Build a To-Do app in Python with Dash (part 2/3) and open the live app here.
- Open your browser’s Developer Tools (press
F12
or right-click on the page and select Inspect). - Navigate to Application (or a similar tab), where you can find Local Storage and Session Storage.

current_index_memory
and list_data_memory
. The other entries (iconify-count
and iconify-version
) are from a third-party library.You will find the Local Storage and Session Storage list. However, store components using storage_type="memory"
will not appear: the data is stored as a React state. It’s encapsulated in the JavaScript memory of the page and is not easily accessible. It’s also not particularly useful to access it directly.
When clicking, you can see the list of dcc.Store
keys. Each store will have one entry for the content (JSON-serialized) and one entry for the modified_timestamp
.
A few important notes:
- Confidentiality: Notice how visible the information stored in a store component is to the end user! In the example above, the entire list of tasks is clearly visible. As a result, you should always remember not to store any confidential information in a
dcc.Store
component. This is especially true forlocalStorage
, which can persist indefinitely (someone accessing your Dash app months later could see the same data as another user from months prior). - Sharing storage:
localStorage
andsessionStorage
are shared with other libraries in your app. So if you use third-party libraries, you may see their entries here. For example, I use a chatbot in one of my apps, and this chatbot extension stores its own info inlocalStorage
.
Pro-tip #1: When working with storage_type="local"
, remember to delete your local storage entries when you need to simulate a fresh app initialization.
Pro-tip #2: If you develop many apps at the same local URL (e.g., http://127.0.0.1:8050/
), you can accidentally overwrite your local storage data across apps if you use the same store IDs. Keep this in mind to avoid unexpected bugs!
Some best practices for dcc.Store
➡️ Serialize data properly
A common error is attempting to store non-JSON-serializable objects, such as Pandas DataFrames, NumPy arrays, or custom Python objects. Since dcc.Store
supports only JSON-compatible data, make sure to convert these objects first (using .to_json()
, .tolist()
, json.dumps()
, etc.):
TypeError: Object of type DataFrame is not JSON serializable.
If your data is not JSON serializable, it’s a strong indication that you should rely on an external source (e.g. a database). Note that for small images, you can still encode them in base64 to get a string.
➡️ Don’t store large objects or DataFrames
Avoid storing large datasets in dcc.Store
. It’s better to use an external database and only store dataset IDs in the dcc.Store
component.
There’s no hard limit for maximum size—it depends on your bandwidth and dataset. However, I would recommend keeping it under 10 MB for high-speed connections, 100KB-1MB for a production ready app.
Good to know: If you want to see a practical example of the impact it can have and how to debug performance issues with network development tools, see here: Dash app callback performance: a real-world debugging example
➡️ Use the right storage type
Select storage type memory
, session
, or local
based on how long the data should persist. If you don’t need any persistence, keep it light with memory
or session
. And remember that you have a limited amount of storage made possible by the browser.
➡️ Trigger callbacks efficiently
You can use the modified_timestamp
property instead of data
if you only need the store as a trigger (without the data itself). This reduces the data transmitted over the network. You can also use modified_timestamp
to trigger a callback at initialization time.
Good to know: See an example of how you can use modified_timestamp
instead of data
here.
Conclusion
I hope this article was helpful. My goal was to provide complementary information to the official documentation! 🙂
dcc.Store
is an essential component that simplifies state management in Dash apps. By using it, you can avoid redundant computations, maintain user session data, and enhance performance. As your app grows, choosing the right storage type and structuring your callbacks efficiently will become increasingly important.
If you want to learn more, take a look at the To-Do app tutorial, which provides a practical example of how to use dcc.Store
: Build a To-Do app in Python with Dash (part 1/3).
If you have any questions, feel free to ask on the Plotly forum here.
Happy coding ⭐!