<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Archives des storage | dash-resources.com</title>
	<atom:link href="https://dash-resources.com/tag/storage/feed/" rel="self" type="application/rss+xml" />
	<link>https://dash-resources.com/tag/storage/</link>
	<description>Learn to build interactive web applications with Python and Dash plotly</description>
	<lastBuildDate>Tue, 17 Feb 2026 23:07:03 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://dash-resources.com/wp-content/uploads/2024/12/cropped-dash-logo-favicon-512-32x32.png</url>
	<title>Archives des storage | dash-resources.com</title>
	<link>https://dash-resources.com/tag/storage/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>The dark side of allow_duplicate &#038; making callbacks sequential</title>
		<link>https://dash-resources.com/avoiding-desynchronized-state-in-dash-sequential-callbacks-patch-and-better-design-patterns/</link>
		
		<dc:creator><![CDATA[Fran]]></dc:creator>
		<pubDate>Tue, 25 Mar 2025 16:29:47 +0000</pubDate>
				<category><![CDATA[Intermediate level]]></category>
		<category><![CDATA[callbacks]]></category>
		<category><![CDATA[storage]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://dash-resources.com/?p=828</guid>

					<description><![CDATA[<p>I was inspired by this question on the Plotly community forum to talk about sequential callbacks and, more broadly, callback design with or without allow_duplicate. [...]</p>
<p>L’article <a href="https://dash-resources.com/avoiding-desynchronized-state-in-dash-sequential-callbacks-patch-and-better-design-patterns/">The dark side of allow_duplicate &amp; making callbacks sequential</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I was inspired by <a href="https://community.plotly.com/t/execution-of-callbacks-writting-to-a-single-dcc-store/91448/3">this question</a> on the Plotly community forum to talk about sequential callbacks and, more broadly, callback design with or without <code>allow_duplicate</code>.</p>



<p>Ensuring that some information is stored without desynchronization issues with callbacks is also a problem that I encountered a few times when developing Dash applications. As a result, I want to discuss here a few solutions and when to approach them.</p>


        
            
            <div class="fit_content">
                <div class="bd_toc_container" data-fixedWidth="">
                    <div class="bd_toc_wrapper" data-wrapperPadding="48px">
                        <div class="bd_toc_wrapper_item">
                            <div class="bd_toc_header active" data-headerPadding="2px">
                                <div class="bd_toc_header_title">
                                    Table of Contents                                </div>
                                <div class="bd_toc_switcher_hide_show_icon">
                                    <span class="bd_toc_arrow"></span>                                </div>
                            </div>
                            <div class="bd_toc_content list-type-disc">
                                <div class="bd_toc_content_list ">
                                    <div class='bd_toc_content_list_item'>    <ul>
      <li class="first">
        <a href="#the-problem">The problem</a>
      </li>
      <li>
        <a href="#solution-1-chaining-callbacks">Solution 1: chaining callbacks</a>
      </li>
      <li>
        <a href="#solution-2-rewriting-callbacks">Solution 2: rewriting callbacks</a>
      </li>
      <li>
        <a href="#solution-3-using-intermediary-stores">Solution 3: using intermediary stores</a>
      </li>
      <li>
        <a href="#solution-4-using-partial-update">Solution 4: using Partial Update</a>
      </li>
      <li class="last">
        <a href="#conclusion">Conclusion</a>
      </li>
    </ul>
</div>                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="layout_toggle_button">
                        <span class="bd_toc_arrow"></span>
                    </div>
                </div>
            </div>




<p>Let&#8217;s dive in <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h2 id='the-problem'  id="boomdevs_1" class="wp-block-heading" >The problem</h2>



<p>Imagine you have a <code>dcc.Store("user_data")</code> that stores something like <code>{"firstname": "John", "lastname": "Doe", "age": 50, ...}</code>. This Store is set via multiple inputs: first_name, last_name, age, …It is a large dictionary and you might have multiple callbacks updating it.</p>



<p>To update this <code>user_data</code> from many inputs, you can set <code>allow_duplicate=True</code>. That way, you are not restricted to only one callback for this output. You just need to get the full <code>user_data</code> back each time (as a State), modify it, and return it.</p>



<p>The code would be something like:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">@callback(
    Output("user_data", "data", allow_duplicate=True),
    Input("first_name", "value"),
    State("user_data", "data"),
    prevent_initial_call=True,
)
def update_first_name(first_name, user_data):

    # Just update user_data with the first name
    if first_name: 
        user_data["first_name"] = first_name
        return user_data

    raise PreventUpdate

@callback(
    Output("user_data", "data", allow_duplicate=True),
    Input("last_name", "value"),
    State("user_data", "data"),
    prevent_initial_call=True,
)
def update_last_name(last_name, user_data):

    # Just update user_data with the last name
    if last_name: 
        user_data["last_name"] = last_name
        return user_data

    raise PreventUpdate

# ... other callbacks</code></pre>



<p>For the moment, everything is fine. But a problem starts appearing if you trigger all inputs at the same time, e.g. to set initial values:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># A callback to simulate the desynchro problem.
# As it triggers the first name and last name input as the same time
@app.callback(
    Output("first_name", "value"),
    Output("last_name", "value"),
    Input("load_data", "n_clicks"),
)
def load_data(n_clicks):
    if n_clicks:
        return "Mickael", "Jackson"
    raise PreventUpdate</code></pre>



<p>A de-synchronization problem appears, between the inputs and the result in the <code>user_dict</code> memory store. The inputs have the updated values, not the stored memory <code>user_dict</code>.</p>



<p>You can try it below (or <a href="https://scripts.dash-resources.com/sequential/app.py/">click here</a>):  </p>



<ul class="wp-block-list">
<li>if you enter &#8220;john&#8221; and &#8220;doe&#8221;, then everything gets updated correctly.</li>



<li>then click on &#8220;load&#8221; data. the <code>user_data</code> should contains firstname = &#8220;mickael&#8221; and lastname = &#8220;jackson&#8221;, but instead some discrepency appears.</li>
</ul>



<iframe src="https://scripts.dash-resources.com/sequential/app.py/" width="100%" height="600" frameBorder="0"></iframe>



<p><strong>Why this problem appears.</strong></p>



<p>Both callbacks are run at the same time. If <code>update_first_name</code> is triggered at the same time <code>update_last_name</code> is triggered, the state value of <code>user_data</code> do not contains the updated first name. It also works the way around, which explains that sometimes we don&#8217;t have the first name, and sometimes the last name. it depends which callback is fired first.</p>



<p>And having <code>Input("user_data", "value")</code> instead of <code>State("user_data", "value")</code> might be possible in some cases, but you would end up with some weird behavior due to the circular pattern. If you have 5 or 10 callbacks following the same scheme, your app will basically blow up because of all the callbacks triggered in all directions. </p>



<p>Here is a video example with 4 inputs:</p>



<figure class="wp-block-video"><video height="1266" style="aspect-ratio: 1964 / 1266;" width="1964" controls src="https://dash-resources.com/wp-content/uploads/2025/03/dash-too-many-circular-callbacks.mp4"></video><figcaption class="wp-element-caption">Illustration: 4 inputs with circular callbacks. Each input modification generates a lot of callback requests.</figcaption></figure>



<p><strong>Notice how many callbacks </strong>are triggered with a single change in one input (1 HTTP request = 1 callback)! Because of the circular scheme, callbacks get triggered unecessarily.</p>



<p>The solution can be to ensure that callbacks are executed sequentially: first <code>update_first_name</code>, and then <code>update_last_name</code>, with the updated value of <code>user_data</code>. That&#8217;s actually what it &#8220;seems to be&#8221;, but the real solution is to think about the problem differently.</p>



<p>But let&#8217;s see why.</p>



<h2 id='solution-1-chaining-callbacks'  id="boomdevs_2" class="wp-block-heading" >Solution 1: chaining callbacks</h2>



<p>How do we make callbacks sequential?</p>



<p>Chaining is the simplest form of sequential callbacks. In that case, you just need to connect one of the outputs of the first callback as an input for the second callback (A -&gt; o -&gt; B -&gt; o).</p>



<p>But as I said previously, we cannot set <code>user_data</code> as an input for the second callback (because of circular dependencies).</p>



<p>Instead, we can use an intermediary <code>dcc.Store</code>, that will just be used as a trigger. I think a timestamp is a good fit for this purpose:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">@callback(
    Output("user_data", "data", allow_duplicate=True),
    Output("intermediary_timestamp", "data"),
    Input("first_name", "value"),
    State("user_data", "data"),
    prevent_initial_call=True,
)
def update_first_name(first_name, user_data):

    # Just update user_data with the first name
    if first_name: 
        user_data["first_name"] = first_name
        return user_data, time.time()

    raise PreventUpdate

@callback(
    Output("user_data", "data", allow_duplicate=True),
    Input("last_name", "value"),
    Input("intermediary_timestamp", "data"),
    State("user_data", "data"),
    prevent_initial_call=True,
)
def update_last_name(last_name, timestamp, user_data):

    # Just update user_data with the last name
    if last_name: 
        user_data["last_name"] = last_name
        return user_data

    raise PreventUpdate</code></pre>



<p>In this example, the <code>update_first_name</code> callback will return the <code>user_data</code> and a timestamp. The dash-renderer will know that it has to wait before triggering <code>update_last_name</code> because <code>intermediary_timestamp</code> must be ready before executing it.</p>



<p class="callout"><strong>Pro-tip:</strong> we could have used the property <code>modified_timestamp</code> of our <code>user_data</code> dcc.Store component as an input. i.e., replacing <code>Input("intermediary_timestamp", "data")</code> by <code>Input("user_data", "modified_timestamp")</code>. That works too and we don&#8217;t even need the intermediary dcc.Store <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h2 id='solution-2-rewriting-callbacks'  id="boomdevs_3" class="wp-block-heading" >Solution 2: rewriting callbacks</h2>



<p>But wait wait wait… Should we really need to chain callbacks?<br>Often the best option is to handle the processing of the two callbacks inside the same callback.</p>



<pre class="wp-block-code"><code lang="python" class="language-python">@callback(
    Output("user_data", "data"),
    Input("first_name", "value"),
    Input("last_name", "value"),
    # .. other possible inputs
    State("user_data", "data"),
)
def update_user_data(first_name, user_data):

    # Just update user_data with the first name
    if first_name: 
        user_data["first_name"] = first_name
    if last_name:
        user_data["last_name"] = last_name
    # .. other possible values

    return user_data</code></pre>



<p>And that solves the synchronization problem.</p>



<p>However, it can happen that you don&#8217;t want to get the value from the input if it wasn&#8217;t really triggered.</p>



<p>Hopefully, there is a way to filter which input was really triggered, using <code>ctx.triggered_prop_ids</code> (<a href="https://dash.plotly.com/advanced-callbacks#determining-which-input-has-fired-with-dash.callback_context">documentation link</a>). Let&#8217;s see an example:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">def slow_processing(user_data):
    # Simulate some long processing, e.g. requesting a database
    time.sleep(4)
    return "Some information"


@callback(
    Output("user_data", "data"),
    Input("first_name", "value"),
    Input("last_name", "value"),
    Input("info_button", "n_clicks"),
    # .. other possible inputs
    State("user_data", "data"),
)
def update_user_data(first_name, last_name, n_clicks, user_data):

    # Identify which inputs were triggered
    first_name_triggered = "first_name" in ctx.triggered_prop_ids.values()
    last_name_triggered = "last_name" in ctx.triggered_prop_ids.values()
    button_triggered = "info_button" in ctx.triggered_prop_ids.values()

    # Update user_data accordingly
    if first_name_triggered and first_name: 
        user_data["first_name"] = first_name
    if last_name_triggered and last_name:
        user_data["last_name"] = last_name

    if button_triggered and n_clicks:
        # An information that takes time to retrieve
        # You want to compute it only if button was *really* triggered
        info = slow_processing(user_data)  
        user_data["info"] = info

    # .. other possible inputs being hanled

    return user_data</code></pre>



<p>The good thing is that this solution is scalable: we can continue adding inputs and keys to our <code>user_data</code> easily. And we get rid of <code>allow_duplicate=True</code> which is useful but also leads to &#8220;callback bad design&#8221;. I&#8217;ll come back to this later.</p>



<h2 id='solution-3-using-intermediary-stores'  id="boomdevs_4" class="wp-block-heading" >Solution 3: using intermediary stores</h2>



<p>Part of the problem that we have here is the use of one memory store for multiple information. </p>



<p>So instead of trying to store everything inside the same callback, we could actually split the <code>user_data</code> dict into as many stores as required: <code>user_first_name</code>, <code>user_last_name</code>, <code>user_age</code>, <code>user_info</code>, etc.</p>



<p>Then, we would have to merge all this information into one callback:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">
app.layout = [
    # ...
    dcc.Store(id="user_first_name"),
    dcc.Store(id="user_last_name"),
    dcc.Store(id="user_age"),
    dcc.Store(id="user_info"),
    # ... other values
]

@callback(
    Output("user_first_name", "data"),
    Input("first_name", "value")
)
def update_first_name(first_name):
    if first_name: 
        return first_name
    raise PreventUpdate

@callback(
    Output("user_last_name", "data"),
    Input("last_name", "value")
)
def update_last_name(last_name):
    if last_name: 
        return last_name
    raise PreventUpdate

@callback(
    Output("user_age", "data"),
    Input("age", "value")
)
def update_age(age):
    if age: 
        return age
    raise PreventUpdate

@callback(
    Output("user_info", "data"),
    Input("info_button", "n_clicks"),
    State("user_data", "data")
)
def update_info(n_clicks, user_data):
    if n_clicks:
        info = slow_processing(user_data) 
        return info
    raise PreventUpdate

# ... other callbacks 

# then we update the user_data:
@callback(
    Output("user_data", "data"),
    Input("user_first_name", "data"),
    Input("user_last_name", "data"),
    Input("user_age", "data"),
    Input("user_info", "data"),
    prevent_initial_call=True,
)
def update_user_data(first_name, last_name, age, info):
    return {
        "first_name": first_name,
        "last_name": last_name,
        "age": age,
        "info": info,
        # ... other properties and values?
    }</code></pre>



<p>If all callbacks are triggered at the same time, <code>update_user_data</code> will be the last one triggered, and all input values will be filled before it can run. That&#8217;s a good way to make callbacks <em>sequential</em>.</p>



<p>The <strong>good</strong> thing about this solution is that we can get rid of <code>allow_duplicate=True</code> too. The <strong>bad</strong> thing is that it is poorly scalable: we would need to add as many stores and callbacks as we have keys to update in <code>user_data</code>.</p>



<p>As you can see, the initial problem was made possible because of <code>allow_duplicate=True</code>. If it wasn&#8217;t an option, we might have used this solution in the first place. And even if it&#8217;s a verbose solution, it&#8217;s a good simple solution. <strong><code>allow_duplicate=True</code> is a fortunate option to use in some cases, but it often leads to bad callback design.</strong></p>



<p class="callout"><strong>Pro-tip:</strong> 99% of the time you don&#8217;t need <code>allow_duplicate=True</code>. Try to avoid it as much as possible. It can creates callback mess.</p>



<h2 id='solution-4-using-partial-update'  id="boomdevs_5" class="wp-block-heading" >Solution 4: using Partial Update</h2>



<p>The above solutions will rely on the fact that we get <code>user_data</code> as a <code>State</code>.<br>But what if <code>user_data</code> is very large? Dash callbacks are HTTP requests, so a large input or state would result in a large HTTP request. Depending on the user&#8217;s bandwidth, it can take time.</p>



<p>Instead, we could use <code>Patch()</code> (<a href="https://dash.plotly.com/partial-properties">documentation link</a>) to only update one key at a time, not the whole <code>user_data</code> dictionary.</p>



<p>Let&#8217;s see the code:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import Patch

@callback(
    Output("user_data", "data", allow_duplicate=True),
    Input("first_name", "value"),
    prevent_initial_call=True,
)
def update_first_name(first_name):

    # Just update user_data with the first name
    if first_name: 
        user_data = Patch()
        user_data["first_name"] = first_name
        return user_data

    raise PreventUpdate

@callback(
    Output("user_data", "data", allow_duplicate=True),
    Input("last_name", "value"),
    prevent_initial_call=True,
)
def update_last_name(last_name):

    # Just update user_data with the last name
    if last_name: 
        user_data = Patch()
        user_data["last_name"] = last_name
        return user_data

    raise PreventUpdate</code></pre>



<p>And that&#8217;s it. :-). <strong>So, how does it works ?</strong> </p>



<ul class="wp-block-list">
<li>In the other solutions, Dash will send the whole <code>user_data</code> to be modified in a callback, gets the new full value, and updates in its storage.  </li>



<li>With Patch(), Dash will just send the input and get just the piece of information that was modified. It then updates the full object in its storage with the new piece of information. </li>



<li>Unless two callbacks modifies the same piece of information (<em>come&#8217;on, you want problems</em>), this solution do not require sequential execution.</li>
</ul>



<p>It&#8217;s maybe the most powerful solution, especially if <code>user_data</code> is very large. It can work with solution n°1, n°2 and n°3. We still use <code>allow_duplicate</code>, but it is not a problem anymore.</p>



<h2 id='conclusion'  id="boomdevs_6" class="wp-block-heading" >Conclusion</h2>



<p>So what&#8217;s the best solution? As always, it depends on your use case.</p>



<p>But here key takeaways:</p>



<ul class="wp-block-list">
<li>If you can, try to avoid using <code>allow_duplicate=True</code> and have one callback update one output</li>



<li>If you can, try to merge multiple callbacks into one callback. It&#8217;s more efficient, and you will de-facto solve the synchronization problem</li>



<li>If you have large data, <code>Patch()</code> is probably the best solution.</li>
</ul>



<p>I hope this article helped you learn about different approaches and how things can get complex with Dash callbacks. Feel free to ask questions or join the discussion here. </p>



<p>Happy coding! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>L’article <a href="https://dash-resources.com/avoiding-desynchronized-state-in-dash-sequential-callbacks-patch-and-better-design-patterns/">The dark side of allow_duplicate &amp; making callbacks sequential</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></content:encoded>
					
		
		<enclosure url="https://dash-resources.com/wp-content/uploads/2025/03/dash-too-many-circular-callbacks.mp4" length="558049" type="video/mp4" />

			</item>
		<item>
		<title>Understanding dcc.Store in Dash Plotly</title>
		<link>https://dash-resources.com/understanding-dcc-store-in-dash-plotly/</link>
		
		<dc:creator><![CDATA[Fran]]></dc:creator>
		<pubDate>Wed, 05 Mar 2025 16:59:05 +0000</pubDate>
				<category><![CDATA[Beginner level]]></category>
		<category><![CDATA[storage]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://dash-resources.com/?p=792</guid>

					<description><![CDATA[<p>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 [...]</p>
<p>L’article <a href="https://dash-resources.com/understanding-dcc-store-in-dash-plotly/">Understanding dcc.Store in Dash Plotly</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Dash applications often require sharing data between callbacks without rerunning expensive computations or relying on an external database. This is where <code>dcc.Store</code> comes in to store your app data on the client side.</p>


        
            
            <div class="fit_content">
                <div class="bd_toc_container" data-fixedWidth="">
                    <div class="bd_toc_wrapper" data-wrapperPadding="48px">
                        <div class="bd_toc_wrapper_item">
                            <div class="bd_toc_header active" data-headerPadding="2px">
                                <div class="bd_toc_header_title">
                                    Table of Contents                                </div>
                                <div class="bd_toc_switcher_hide_show_icon">
                                    <span class="bd_toc_arrow"></span>                                </div>
                            </div>
                            <div class="bd_toc_content list-type-disc">
                                <div class="bd_toc_content_list ">
                                    <div class='bd_toc_content_list_item'><ul>
  <li class="first">
    <span></span>
    <ul class="menu_level_1">
      <li class="first">
        <a href="#what-is-dcc-store-and-why-do-we-need-it">What is dcc.Store, and why do we need it?</a>
        <ul class="menu_level_2">
          <li class="first">
            <a href="#a-bit-of-history">A bit of history</a>
          </li>
          <li>
            <a href="#introduction-to-dcc-store">Introduction to dcc.Store</a>
          </li>
          <li class="last">
            <a href="#why-it-is-needed">Why it is needed</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#understanding-dcc-store-storage-types">Understanding dcc.Store Storage Types</a>
        <ul class="menu_level_2">
          <li class="first last">
            <a href="#how-much-can-you-store">How much can you store?</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#how-to-debug-dcc-store">How to debug dcc.Store</a>
      </li>
      <li class="last">
        <a href="#some-best-practices-for-dcc-store">Some best practices for dcc.Store</a>
        <ul class="menu_level_2">
          <li class="first">
            <a href="#&#x27a1;-serialize-data-properly"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Serialize data properly</a>
          </li>
          <li>
            <a href="#&#x27a1;-don-t-store-large-objects-or-dataframes"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Don’t store large objects or DataFrames</a>
          </li>
          <li>
            <a href="#&#x27a1;-use-the-right-storage-type"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Use the right storage type</a>
          </li>
          <li class="last">
            <a href="#&#x27a1;-trigger-callbacks-efficiently"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Trigger callbacks efficiently</a>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="last">
    <a href="#conclusion">Conclusion</a>
  </li>
</ul>
</div>                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="layout_toggle_button">
                        <span class="bd_toc_arrow"></span>
                    </div>
                </div>
            </div>




<p>In this tutorial, we’ll explore what <code>dcc.Store</code> is, how it works, and best practices for using it effectively in Dash applications.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="callout"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b06.png" alt="⬆" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong> <strong>Level up your Dash skills!</strong> <strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b06.png" alt="⬆" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong> I wrote a full course to help you <a href="https://dash-resources.com/dash-plotly-course/">learn how to think and design a Dash app with simple and advanced callbacks</a>. Real pro-tips, from a real human expert!</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 id='what-is-dcc-store-and-why-do-we-need-it'  id="boomdevs_1" class="wp-block-heading" >What is <code>dcc.Store</code>, and why do we need it?</h2>



<h3 id='a-bit-of-history'  id="boomdevs_2" class="wp-block-heading" >A bit of history</h3>



<p>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.</p>



<p>As a result, the Plotly team introduced <code>dcc.Store</code> in Dash 0.32, and it has become one of the most essential components.</p>



<h3 id='introduction-to-dcc-store'  id="boomdevs_3" class="wp-block-heading" >Introduction to dcc.Store</h3>



<p>The <code>dcc.Store</code> 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.</p>



<p>It has four key properties:</p>



<ul class="wp-block-list">
<li><strong><code>id</code></strong>: Like any other regular Dash component, this is used for callbacks.</li>



<li><strong><code>storage_type</code></strong>: Either <code>memory</code>, <code>session</code>, or <code>local</code> (more on this below).</li>



<li><strong><code>data</code></strong>: The initial value for the store when the app loads.</li>



<li><strong><code>modified_timestamp</code></strong>: The latest modification timestamp.</li>
</ul>



<p>You can create as many <code>dcc.Store</code> components as you need and include them in your app’s layout. Here’s an example:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">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</code></pre>



<p>In this example, we set up a <code>user_id_store</code> 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.</p>



<h3 id='why-it-is-needed'  id="boomdevs_4" class="wp-block-heading" >Why it is needed</h3>



<p>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!).</p>



<p>The <code>dcc.Store</code> 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.  </p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="1718" height="882" src="https://dash-resources.com/wp-content/uploads/2025/03/image.png" alt="" class="wp-image-793" srcset="https://dash-resources.com/wp-content/uploads/2025/03/image.png 1718w, https://dash-resources.com/wp-content/uploads/2025/03/image-300x154.png 300w, https://dash-resources.com/wp-content/uploads/2025/03/image-1024x526.png 1024w, https://dash-resources.com/wp-content/uploads/2025/03/image-768x394.png 768w, https://dash-resources.com/wp-content/uploads/2025/03/image-1536x789.png 1536w" sizes="(max-width: 1718px) 100vw, 1718px" /><figcaption class="wp-element-caption">Illustration: A callback execution involving client-side stored data (with <code>dcc.Store</code>) and database data retrieval and processing.</figcaption></figure>



<p>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.</p>



<p class="callout"><strong>Learn</strong> best practices for callbacks here: <a href="https://dash-resources.com/dash-callbacks-best-practices-with-examples/">Dash callbacks best practices (with examples)</a> </p>



<h2 id='understanding-dcc-store-storage-types'  id="boomdevs_5" class="wp-block-heading" >Understanding <code>dcc.Store</code> Storage Types</h2>



<p>A key feature of <code>dcc.Store</code> is its flexibility in how data is stored. It offers three different storage types, each with unique characteristics:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># 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')</code></pre>



<p>Each storage type serves different purposes:</p>



<ul class="wp-block-list">
<li><strong>Memory (<code>storage_type='memory'</code>)</strong>: 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.</li>



<li><strong>Session (<code>storage_type='session'</code>)</strong>: 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’s <code>sessionStorage</code> API.</li>



<li><strong>Local (<code>storage_type='local'</code>)</strong>: Data persists indefinitely, even after the browser is closed and reopened. This uses the browser’s <code>localStorage</code> API and is great for user preferences or application settings.</li>
</ul>



<p>Your choice depends on your specific requirements. For instance, use <code>local</code> for user preferences that should persist across sessions, <code>session</code> for data that should survive a refresh but not a browser restart, and <code>memory</code> for transient data like intermediate computational results.</p>



<p class="callout"><strong>Pro-tip</strong>: It can be helpful to add a suffix like <code>-store</code> or <code>_memory</code> to all your <code>dcc.Store</code> IDs. This makes it easy to identify which inputs and outputs are stores in your callbacks.</p>



<h3 id='how-much-can-you-store'  id="boomdevs_6" class="wp-block-heading" >How much can you store?</h3>



<p>The amount of data that can be stored in <code>dcc.Store</code> depends on the selected <code>storage_type</code>:</p>



<ul class="wp-block-list">
<li><strong>Memory</strong>: Limited only by the browser’s available memory but cleared on page refresh.</li>



<li><strong>Session and Local</strong>: These rely on the browser’s <code>sessionStorage</code> and <code>localStorage</code> APIs, which typically allow up to <strong>10MB</strong> per domain (<a href="https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria#how_much_data_can_be_stored">source</a>). However, this limit varies between browsers and may be smaller on mobile devices.</li>
</ul>



<p>Additionally, performance considerations matter when using <code>dcc.Store</code> for large datasets. Each time a callback accesses or updates <code>dcc.Store</code>, 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.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 id='how-to-debug-dcc-store'  id="boomdevs_7" class="wp-block-heading" >How to debug <code>dcc.Store</code></h2>



<p>Depending on the storage type, you can inspect, update, or delete storage values, which can be useful during development, especially for <code>session</code> and <code>local</code> types.</p>



<p>For this example, I will use a To-Do app built in Dash. You can find how I created it in this tutorial: <a href="https://dash-resources.com/build-a-to-do-app-in-python-with-dash-part-2-3/">Build a To-Do app in Python with Dash (part 2/3)</a> and open the live app <a href="https://scripts.dash-resources.com/todo_app/app5.py/">here</a>.</p>



<ol class="wp-block-list">
<li>Open your browser’s Developer Tools (press <code>F12</code> or right-click on the page and select <strong>Inspect</strong>).</li>



<li>Navigate to <strong>Application</strong> (or a similar tab), where you can find Local Storage and Session Storage.</li>
</ol>



<figure class="wp-block-image size-full"><img decoding="async" width="2048" height="1418" src="https://dash-resources.com/wp-content/uploads/2025/03/image-1.png" alt="" class="wp-image-794" srcset="https://dash-resources.com/wp-content/uploads/2025/03/image-1.png 2048w, https://dash-resources.com/wp-content/uploads/2025/03/image-1-300x208.png 300w, https://dash-resources.com/wp-content/uploads/2025/03/image-1-1024x709.png 1024w, https://dash-resources.com/wp-content/uploads/2025/03/image-1-768x532.png 768w, https://dash-resources.com/wp-content/uploads/2025/03/image-1-1536x1064.png 1536w" sizes="(max-width: 2048px) 100vw, 2048px" /><figcaption class="wp-element-caption">Illustration: an example of localStorage in my to-do app. We can see the exact content of two dcc.Store components: <code>current_index_memory</code> and <code>list_data_memory</code>. The other entries (<code>iconify-count</code> and <code>iconify-version</code>) are from a third-party library.</figcaption></figure>



<p>You will find the <em>Local Storage</em> and <em>Session Storage</em> list. However, store components using <code>storage_type="memory"</code> 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.</p>



<p>When clicking, you can see the list of <code>dcc.Store</code> keys. Each store will have one entry for the content (JSON-serialized) and one entry for the <code>modified_timestamp</code>.</p>



<p>A few important notes:</p>



<ul class="wp-block-list">
<li><strong>Confidentiality:</strong> Notice how <strong>visible</strong> 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 <strong>not</strong> to store any confidential information in a <code>dcc.Store</code> component. This is especially true for <code>localStorage</code>, which can persist indefinitely (someone accessing your Dash app months later could see the same data as another user from months prior).</li>



<li><strong>Sharing storage:</strong> <code>localStorage</code> and <code>sessionStorage</code> 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 in <code>localStorage</code>.</li>
</ul>



<p class="callout"><strong>Pro-tip #1</strong>: When working with <code>storage_type="local"</code>, remember to delete your local storage entries when you need to simulate a fresh app initialization.<br><br><strong>Pro-tip #2</strong>: If you develop many apps at the same local URL (e.g., <code>http://127.0.0.1:8050/</code>), 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!</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 id='some-best-practices-for-dcc-store'  id="boomdevs_8" class="wp-block-heading" >Some best practices for <code>dcc.Store</code></h2>



<h3 id='&#x27a1;-serialize-data-properly'  id="boomdevs_9" class="wp-block-heading" ><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Serialize data properly</h3>



<p>A common error is attempting to store non-JSON-serializable objects, such as Pandas DataFrames, NumPy arrays, or custom Python objects. Since <code>dcc.Store</code> supports only JSON-compatible data, make sure to convert these objects first (using <code>.to_json()</code>, <code>.tolist()</code>, <code>json.dumps()</code>, etc.):</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em>TypeError: Object of type DataFrame is not JSON serializable.</em></p>
</blockquote>



<p>If your data is not JSON serializable, it&#8217;s a strong indication that you should rely on an external source (e.g. a database). Note that for small images, you can still <a href="https://www.base64-image.de/">encode them in base64</a> to get a string. </p>



<h3 id='&#x27a1;-don-t-store-large-objects-or-dataframes'  id="boomdevs_10" class="wp-block-heading" ><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Don’t store large objects or DataFrames</h3>



<p>Avoid storing large datasets in <code>dcc.Store</code>. It’s better to use an external database and only store dataset IDs in the <code>dcc.Store</code> component.</p>



<p>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.</p>



<p class="callout"><strong>Good to know:</strong> 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: <a href="https://dash-resources.com/dash-app-callback-performance-a-real-world-debugging-example/">Dash app callback performance: a real-world debugging example</a></p>



<h3 id='&#x27a1;-use-the-right-storage-type'  id="boomdevs_11" class="wp-block-heading" ><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Use the right storage type</h3>



<p>Select storage type <code>memory</code>, <code>session</code>, or <code>local</code> based on how long the data should persist. If you don’t need any persistence, keep it light with <code>memory</code> or <code>session</code>. And remember that you have a limited amount of storage made possible by the browser.</p>



<h3 id='&#x27a1;-trigger-callbacks-efficiently'  id="boomdevs_12" class="wp-block-heading" ><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Trigger callbacks efficiently</h3>



<p>You can use the <code>modified_timestamp</code> property instead of <code>data</code> 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 <code>modified_timestamp</code> to trigger a callback at initialization time. </p>



<p class="callout"><strong>Good to know: </strong>See an example of how you can use <code>modified_timestamp</code> instead of <code>data</code> here.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 id='conclusion'  id="boomdevs_13" class="wp-block-heading" >Conclusion</h1>



<p>I hope this article was helpful. My goal was to provide complementary information to the <a href="https://dash.plotly.com/dash-core-components/store">official documentation</a>! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p><code>dcc.Store</code> 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.</p>



<ul class="wp-block-list">
<li>If you want to learn more, take a look at the To-Do app tutorial, which provides a practical example of how to use <code>dcc.Store</code>: <a href="https://dash-resources.com/build-a-to-do-app-in-python-with-dash-part-1-3/">Build a To-Do app in Python with Dash (part 1/3)</a>.</li>



<li>If you have any questions, feel free to ask on the Plotly forum <a href="https://community.plotly.com/t/a-dcc-store-tutorial-how-it-works-storage-types-and-more/90866">here</a>.</li>
</ul>



<p>Happy coding <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" />!</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="callout"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b06.png" alt="⬆" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong> <strong>Level up your Dash skills!</strong> <strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b06.png" alt="⬆" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong> I wrote a full course to help you <a href="https://dash-resources.com/dash-plotly-course/">learn how to think and design a Dash app with simple and advanced callbacks</a>. Real pro-tips, from a real human expert!</p>
<p>L’article <a href="https://dash-resources.com/understanding-dcc-store-in-dash-plotly/">Understanding dcc.Store in Dash Plotly</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
