<?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 callbacks | dash-resources.com</title>
	<atom:link href="https://dash-resources.com/tag/callbacks/feed/" rel="self" type="application/rss+xml" />
	<link>https://dash-resources.com/tag/callbacks/</link>
	<description>Learn to build interactive web applications with Python and Dash plotly</description>
	<lastBuildDate>Wed, 18 Feb 2026 09:08:44 +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 callbacks | dash-resources.com</title>
	<link>https://dash-resources.com/tag/callbacks/</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>Dash callbacks best practices (with examples)</title>
		<link>https://dash-resources.com/dash-callbacks-best-practices-with-examples/</link>
		
		<dc:creator><![CDATA[Fran]]></dc:creator>
		<pubDate>Mon, 30 Dec 2024 20:47:45 +0000</pubDate>
				<category><![CDATA[Intermediate level]]></category>
		<category><![CDATA[callbacks]]></category>
		<guid isPermaLink="false">https://dash-resources.com/?p=203</guid>

					<description><![CDATA[<p>As a Dash app grows, it is easy to get lost in the complexity of interconnected, large callbacks handling a lot of functionality. How can [...]</p>
<p>L’article <a href="https://dash-resources.com/dash-callbacks-best-practices-with-examples/">Dash callbacks best practices (with examples)</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>As a Dash app grows, it is easy to get lost in the complexity of interconnected, large callbacks handling a lot of functionality. How can you keep your app manageable? What are the best practices when it comes to Dash callbacks?</p>



<p>Over the years, I’ve developed and maintained apps either on my own or with different teams. In this tutorial, I’ll share five good practices, based on my experience, to help you better organize your Dash callbacks.</p>



<p><strong>See also:</strong> <a href="https://dash-resources.com/writing-in-process/">Dash development best practices</a></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="#1-separate-layouts-from-callbacks">1. Separate layouts from callbacks</a>
        <ul class="menu_level_2">
          <li class="first last">
            <a href="#example">Example</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#2-make-your-callbacks-readable">2. Make your callbacks readable</a>
        <ul class="menu_level_2">
          <li class="first last">
            <a href="#example-1">Example</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#3-don-t-oversplit-callbacks">3. Don’t oversplit callbacks</a>
        <ul class="menu_level_2">
          <li class="first last">
            <a href="#example-2">Example</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#4-avoid-big-callbacks-too">4. Avoid big callbacks too</a>
        <ul class="menu_level_2">
          <li class="first last">
            <a href="#example-3">Example</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#5-chain-callbacks-intelligently">5. Chain callbacks intelligently</a>
        <ul class="menu_level_2">
          <li class="first last">
            <a href="#example-4">Example</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#6-other-good-practices">6. Other good practices</a>
        <ul class="menu_level_2">
          <li class="first">
            <a href="#avoid-using-suppress-callback-exceptions">Avoid using suppress_callback_exceptions</a>
          </li>
          <li>
            <a href="#use-prevent-initial-call-when-possible">Use prevent_initial_call when possible</a>
          </li>
          <li>
            <a href="#use-preventupdate">Use PreventUpdate</a>
          </li>
          <li class="last">
            <a href="#use-dcc-store">Use dcc.Store</a>
          </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>Let’s dive in! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f604.png" alt="😄" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



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



<h2 id='1-separate-layouts-from-callbacks'  id="boomdevs_1" class="wp-block-heading" >1. Separate layouts from callbacks</h2>



<p>It’s really common to see callbacks, layouts, and data processing in the same file. Many people develop the first version of their app quickly, and it’s too early to think about organization. However, if your plan is to make the application easy to maintain, you must adopt a better project structure.</p>



<p>There are many ways to achieve this. I personally follow something that resembles the MVC pattern:</p>



<ul class="wp-block-list">
<li>Create new folders: <code>callbacks</code>, <code>layouts</code>, and <code>utils</code>.</li>



<li>Create separate files for each part of your app in the <code>callbacks</code> and <code>layouts</code> folders.</li>
</ul>



<h3 id='example'  id="boomdevs_2" class="wp-block-heading" >Example</h3>



<p>The following is an example architecture. The one that I personnaly use in my projects is very similar:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># Example folder structure
app/
  ├── callbacks/
  │   ├── sales_dashboard.py    # All sales-related callbacks
  │   ├── inventory.py          # All inventory-related callbacks
  │   └── user_settings.py      # User preferences callbacks
  ├── layouts/
  │   ├── sales_dashboard.py    # Sales dashboard layout
  │   ├── inventory.py          # Inventory management layout
  │   └── user_settings.py      # Settings page layout
  ├── utils/
  │   └── data_utils.py         # Data preprocessing functions
  └── app.py</code></pre>



<p>In the <code>app.py</code> file, the code becomes more readable:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># app.py
from dash import Dash
from layouts.sales_dashboard import get_sales_dashboard_layout
from layouts.inventory import get_inventory_layout
from layouts.user_settings import get_user_settings_layout
from callbacks.sales_dashboard import *
from callbacks.inventory import *
from callbacks.user_settings import *

app = Dash(__name__)
app.layout = html.Div([
    get_sales_dashboard_layout(),
    get_inventory_layout(),
    get_user_settings_layout(),
])

# Run the app
if __name__ == '__main__':
    app.run_server(debug=True)</code></pre>



<p>With this architecture, callbacks centralize the logic of each part of the app. They rely on <code>utils</code> to load and process data and <code>layouts</code> functions to update graphs, tables, etc.</p>



<p>See below for an example callback in <code>callbacks/sales_dashboard.py</code>.</p>



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



<h2 id='2-make-your-callbacks-readable'  id="boomdevs_3" class="wp-block-heading" >2. Make your callbacks readable</h2>



<p>It’s common to start doing everything within the callback. This results in many callbacks with 10-50 lines of code, making them hard to read. A good rule of thumb is to keep a callback concise and clear.</p>



<p>You should be able to understand what the callback does just by looking at the inputs, outputs, and a few lines of code (as in the previous example).</p>



<h3 id='example-1'  id="boomdevs_4" class="wp-block-heading" >Example</h3>



<p>Here’s an example. How much time do you need to understand the following callback?</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># Hard-to-read callback - too much happening
@app.callback(
    Output('sales-graph', 'figure'),
    [Input('date-picker', 'value'),
     Input('product', 'value')]
)
def update_graph(date, product):
    # Load data
    df = pd.read_csv('sales.csv')

    # Complex data processing inside callback
    df['date'] = pd.to_datetime(df['date'])
    df = df[df['date'] &gt;= date]
    df = df[df['product'] == product]

    # Calculate metrics
    total_sales = df['amount'].sum()
    avg_sale = df['amount'].mean()

    # Create figure with multiple traces
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=df['date'], y=df['amount'], name='Sales'))
    fig.add_trace(go.Scatter(x=df['date'], y=df['amount'].rolling(7).mean(), name='7-day average'))

    # Complex layout settings
    fig.update_layout(
        title=f'Sales for {product}: Total ${total_sales:,.2f}, Average ${avg_sale:.2f}',
        xaxis_title='Date',
        yaxis_title='Amount',
        hovermode='x unified'
    )
    return fig</code></pre>



<p>I&#8217;m pretty sure it took some time. Now let’s outsource each part into functions saved in other files (following advice #1):</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># callbacks/sales_dashboard.py
from layouts.sales_dashboard import create_sales_figure
from utils.data_utils import load_and_filter_data   

@app.callback(
    Output('sales-graph', 'figure'),
    [Input('date-picker', 'value'),
     Input('product', 'value')]
)
def update_graph(date, product):
    df = load_and_filter_data(date, product)
    fig = create_sales_figure(df)
    return fig</code></pre>



<p>Now, how much time did it take you to understand this code? <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f603.png" alt="😃" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>The callback function doesn&#8217;t even need to be commented. The code speaks for itself, is easily understandable, and is easy to maintain. Future developers on the project will immediately understand what is going on!</p>



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



<h2 id='3-don-t-oversplit-callbacks'  id="boomdevs_5" class="wp-block-heading" >3. Don’t oversplit callbacks</h2>



<p>I generally advocate for a “<a href="https://en.wikipedia.org/wiki/Divide-and-conquer_algorithm">divide-and-conquer</a>” approach, which encourages making small, atomic functions. However, in the case of callbacks, it’s not always the best option. Making small callbacks increases the number of HTTP requests needed, thus increasing latency and unnecessary server rounds.</p>



<h3 id='example-2'  id="boomdevs_6" class="wp-block-heading" >Example</h3>



<p>Here’s an example. The first version splits a simple calculation into two callbacks, creating unnecessary complexity:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># Unnecessarily split version
@app.callback(
    Output('temp-celcius', 'children'),
    Input('temperature', 'value')
)
def convert_to_celsius(fahrenheit):
    celsius = (fahrenheit - 32) * 5/9
    return f"{celsius:.1f}°C"

@app.callback(
    Output('temp-kelvin', 'children'),
    Input('temp-celcius', 'children')
)
def convert_to_kelvin(celsius_text):
    celsius = float(celsius_text.replace('°C', ''))
    kelvin = celsius + 273.15
    return f"{kelvin:.1f}K"</code></pre>



<p>Let’s rewrite this as a single callback:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># Better as one callback
@app.callback(
    [Output('temp-celcius', 'children'),
     Output('temp-kelvin', 'children')],
    Input('temperature', 'value')
)
def convert_temperature(fahrenheit):
    celsius = (fahrenheit - 32) * 5/9
    kelvin = celsius + 273.15
    return f"{celsius:.1f}°C", f"{kelvin:.1f}K"</code></pre>



<p>This version combines the conversions into a single callback. It simplifies the code, eliminates the need for string parsing, and reduces the number of callback executions. The calculations are closely related and simple enough that splitting them provides no benefit.</p>



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



<h2 id='4-avoid-big-callbacks-too'  id="boomdevs_7" class="wp-block-heading" >4. Avoid big callbacks too</h2>



<p>On the other hand, making big callbacks that handle everything isn’t a good option either. But how do you know if a callback should be split or restructured?</p>



<p>A good rule of thumb is to aim for callbacks with inputs and outputs that naturally group together, i.e., share the same purpose.</p>



<h3 id='example-3'  id="boomdevs_8" class="wp-block-heading" >Example</h3>



<p>Here’s an example. This callback handles both the update of a chart and the creation of an alert:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># Bad example: One callback doing too many unrelated things
@app.callback(
    [Output('sales-chart', 'figure'),
     Output('alerts', 'children')],
    [Input('date-range', 'value'),
     Input('threshold', 'value')]
)
def update_everything(date_range, threshold):
    # This callback mixes two very different responsibilities:
    # 1. Sales visualization
    # 2. Alert system for unusual patterns

    sales_data = get_sales_data(date_range)

    # Create sales visualization
    fig = create_sales_chart(sales_data)

    # Also handle complex alert logic
    unusual_patterns = detect_anomalies(sales_data, threshold)
    alert_messages = generate_alert_messages(unusual_patterns)

    return fig, alert_messages</code></pre>



<p>Now let’s split this callback into two, each with a separate purpose:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># Better: Split into two callbacks with clear, separate purposes
@app.callback(
    Output('sales-chart', 'figure'),
    Input('date-range', 'value')
)
def update_sales_chart(date_range):
    # Only handles visualization
    sales_data = get_sales_data(date_range)
    return create_sales_chart(sales_data)

@app.callback(
    Output('alerts', 'children'),
    [Input('date-range', 'value'),
     Input('threshold', 'value')]
)
def update_alerts(date_range, threshold):
    # Only handles the alert system
    sales_data = get_sales_data(date_range)
    unusual_patterns = detect_anomalies(sales_data, threshold)
    return generate_alert_messages(unusual_patterns)</code></pre>



<p>Even though the original code avoids repetition and combines a common input (<code>date-range</code>), it is badly designed. Poor design will eventually complicate debugging. The split version brings the following benefits:</p>



<ul class="wp-block-list">
<li>Each callback has its own clear purpose → easier to add functionalities in the future.</li>



<li>Debugging one callback is easier as it has no impact on the other.</li>



<li>Visualization can be updated without re-triggering the alert logic, and vice versa.</li>
</ul>



<p>The key takeaway is that callbacks should be split when they handle logically separate features, not just to make them smaller.</p>



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



<h2 id='5-chain-callbacks-intelligently'  id="boomdevs_9" class="wp-block-heading" >5. Chain callbacks intelligently</h2>



<p>The way we chain callbacks in Dash Plotly can sometimes resemble the <code>goto</code> instruction in programming languages like C. The <code>goto</code> statement allows the program to jump arbitrarily from one part of the code to another, a practice <a href="https://en.wikipedia.org/wiki/Goto#Criticism">often criticized</a> for leading to &#8220;<a href="https://en.wikipedia.org/wiki/Spaghetti_code">spaghetti code</a>&#8220;—code that is difficult to debug, understand, and maintain.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" width="1024" height="1024" src="https://dash-resources.com/wp-content/uploads/2024/12/image-3.png" alt="" class="wp-image-208" style="width:520px;height:auto" srcset="https://dash-resources.com/wp-content/uploads/2024/12/image-3.png 1024w, https://dash-resources.com/wp-content/uploads/2024/12/image-3-300x300.png 300w, https://dash-resources.com/wp-content/uploads/2024/12/image-3-150x150.png 150w, https://dash-resources.com/wp-content/uploads/2024/12/image-3-768x768.png 768w, https://dash-resources.com/wp-content/uploads/2024/12/image-3-400x400.png 400w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>Dash&#8217;s callback system, while powerful, can introduce similar challenges if not carefully managed. As callbacks depend on specific input-output relationships, a poorly structured app can quickly become tangled and confusing, with callbacks triggering each other in complex and unintended ways.</p>



<p>Here is a list of ideas to avoid this:</p>



<ul class="wp-block-list">
<li>If you follow advice n°2, try to avoid chaining callbacks from a callback file to another callback file.</li>



<li>Avoid connecting a bottom component with a top callback. Instead, try to compute the information of this component upfront.</li>



<li>As the code changes, some inputs may not be required anymore for a callback. Removing useless inputs will reduce the overall complexity of the app. </li>



<li>Changing an <code>Input</code> to a <code>State</code> when it&#8217;s not needed can as well reduce the complexity of an app.</li>
</ul>



<h3 id='example-4'  id="boomdevs_10" class="wp-block-heading" >Example</h3>



<p>Let&#8217;s see take a look at this code : </p>



<pre class="wp-block-code"><code lang="python" class="language-python"># Poor callback organization - "spaghetti" chaining
# callbacks_layout1.py
@app.callback(
    Output('top-chart', 'figure'),
    Input('date-picker', 'value')
)
def update_top_chart(date):
    return create_top_figure(date)

# callbacks_layout2.py
@app.callback(
    Output('middle-stats', 'children'),
    Input('top-chart', 'clickData')
)
def update_middle_stats(click_data):
    point = click_data['points'][0]
    return calculate_stats(point)

# callbacks_layout3.py
@app.callback(
    Output('bottom-table', 'data'),
    Input('middle-stats', 'children')
)
def update_bottom_table(stats):
    # Fragile: depends on parsing text from middle component
    value = float(stats.split(': ')[1])
    return get_table_data(value)</code></pre>



<p>The first version creates a chain of dependencies across different files, where each component waits for updates from the previous one. This makes the code fragile (parsing text from UI elements), hard to debug (dependencies spread across files), and inefficient (cascading updates).</p>



<p>The improved version:</p>



<pre class="wp-block-code"><code lang="python" class="language-python"># Better organization - reduce dependencies, compute data upfront
# callbacks.py
def get_full_data(date):
    """Compute all required data at once"""
    df = load_data(date)
    return {
        'chart_data': prepare_chart_data(df),
        'stats': calculate_stats(df),
        'table_data': prepare_table_data(df)
    }

@app.callback(
    [Output('top-chart', 'figure'),
     Output('middle-stats', 'children'),
     Output('bottom-table', 'data')],
    Input('date-picker', 'value')
)
def update_dashboard(date):
    data = get_full_data(date)
    return (
        create_top_figure(data['chart_data']),
        format_stats(data['stats']),
        data['table_data']
    )

# If click interaction is needed, keep it separate
@app.callback(
    Output('detail-view', 'children'),
    Input('top-chart', 'clickData')
)
def show_details(click_data):
    if click_data is None:
        return "Click a point for details"</code></pre>



<p>The improved version front-loads data processing and groups related callbacks together. By streamlining dependencies and keeping data flow clear, while separating interactive features, the code becomes more maintainable.</p>



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



<h2 id='6-other-good-practices'  id="boomdevs_11" class="wp-block-heading" >6. Other good practices</h2>



<h3 id='avoid-using-suppress-callback-exceptions'  id="boomdevs_12" class="wp-block-heading" >Avoid using <code>suppress_callback_exceptions</code></h3>



<p>I think it’s not a good practice to use <code>suppress_callback_exceptions</code>. If a component is missing but shouldn’t be, this should raise an error. Explicit errors help you understand the problem more quickly. Implicit errors will waste your time.</p>



<p>If you can’t avoid setting <code>suppress_callback_exceptions=True</code>, it likely means you need to rethink your app layout. You could rely on <a>pattern-matching callbacks</a> for components created at runtime.</p>



<h3 id='use-prevent-initial-call-when-possible'  id="boomdevs_13" class="wp-block-heading" >Use <code>prevent_initial_call</code> when possible</h3>



<p>Dash executes callbacks at least once during app initialization by default. If a callback doesn’t need to be executed at first, you can disable its initial execution with <code>prevent_initial_call</code>. This reduces the number of initial callbacks triggered during loading.</p>



<h3 id='use-preventupdate'  id="boomdevs_14" class="wp-block-heading" >Use <code>PreventUpdate</code></h3>



<p><code>PreventUpdate</code> is a great way to catch errors, e.g., when a value is <code>None</code> or isn’t supposed to be what it is.</p>



<p>Using <code>PreventUpdate</code> helps stop unnecessary callback chaining, reducing the number of updates and HTTP requests. This is a performance tip, but it also simplifies debugging.</p>



<h3 id='use-dcc-store'  id="boomdevs_15" class="wp-block-heading" >Use <code>dcc.Store</code></h3>



<p>You can sometimes use <code>dcc.Store</code> to compute and store results. If the stored data is based on inputs, you instantly reduce the number of inputs needed for dependent callbacks, making them more readable.</p>



<p>However, avoid saving heavy data in <code>dcc.Store</code> (e.g., keep it under 1 MB). Large data slows down the app because it must be both downloaded and uploaded from the client.</p>



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



<div class="wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-ad2f72ca wp-block-group-is-layout-flex">
<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"/>
</div>



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



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



<p>What you need to remember is that half the work of keeping callbacks easy to understand is using a well-organized structure.</p>



<ul class="wp-block-list">
<li><strong>Don’t wait too long to refactor your callback function</strong>s. If they get too big, externalize functions to make the callbacks easier to read.</li>
</ul>



<ul class="wp-block-list">
<li><strong>Don’t oversplit logic into many callbacks</strong>, <strong>but avoid processing everything in a single callback </strong>with all inputs and outputs either. Remember the general rule of thumb to create “natural groups”.</li>
</ul>



<p>Everything presented in this article isn’t an absolute truth. As the framework evolves, so do best practices. But this should help you grow your app from a simple single-page dashboard into a full interactive platform.</p>



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



<p>I hope you learned something from this article! <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;" /> Be sure to subscribe to the newsletter to see the next ones, and check out the <a href="https://dash-resources.com/dash-plotly-course/">courses</a>.</p>
<p>L’article <a href="https://dash-resources.com/dash-callbacks-best-practices-with-examples/">Dash callbacks best practices (with examples)</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Tutorial: Dash callbacks (schemas &#038; examples)</title>
		<link>https://dash-resources.com/tutorial-dash-callbacks-schemas-examples/</link>
		
		<dc:creator><![CDATA[Fran]]></dc:creator>
		<pubDate>Sun, 29 Dec 2024 15:13:12 +0000</pubDate>
				<category><![CDATA[Beginner level]]></category>
		<category><![CDATA[callbacks]]></category>
		<guid isPermaLink="false">https://dash-resources.com/?p=120</guid>

					<description><![CDATA[<p>At its core, Dash Plotly uses a system of &#8220;callbacks&#8221; to create interactive features &#8211; these are Python functions that automatically update parts of your [...]</p>
<p>L’article <a href="https://dash-resources.com/tutorial-dash-callbacks-schemas-examples/">Tutorial: Dash callbacks (schemas &amp; examples)</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>At its core, Dash Plotly uses a system of &#8220;callbacks&#8221; to create interactive features &#8211; these are Python functions that automatically update parts of your application in response to user inputs.</p>



<p>There are many ways to design Dash callbacks, and in this dash callbacks tutorial, I&#8217;ll provide a comprehensive, <strong>step-by-step guide with diagrams and code examples</strong>. </p>



<p>By the end of this tutorial, you&#8217;ll have a good understanding of how callbacks work and how to implement interactivity in your own Dash applications.</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="#a-simple-callback">A simple callback</a>
      </li>
      <li>
        <a href="#multi-input-callback">Multi input callback</a>
      </li>
      <li>
        <a href="#multiple-inputs-and-outputs-callbacks">Multiple inputs and outputs callbacks</a>
      </li>
      <li>
        <a href="#multiple-callbacks-with-the-same-inputs">Multiple callbacks with the same inputs</a>
      </li>
      <li>
        <a href="#chained-callbacks-callbacks-triggering-other-callbacks">Chained callbacks: callbacks triggering other callbacks</a>
        <ul class="menu_level_2">
          <li class="first">
            <a href="#using-state-instead-of-input">Using State instead of Input</a>
          </li>
          <li class="last">
            <a href="#advantages-and-disadvantages-of-chaining-callbacks">Advantages and disadvantages of chaining callbacks</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#other-types-of-callbacks">Other types of callbacks</a>
        <ul class="menu_level_2">
          <li class="first">
            <a href="#background-callbacks">Background Callbacks</a>
          </li>
          <li>
            <a href="#clientside-callbacks">Clientside Callbacks</a>
          </li>
          <li class="last">
            <a href="#pattern-matching-callbacks">Pattern-Matching Callbacks</a>
          </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>Let&#8217;s start! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4aa.png" alt="💪" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h2 id='a-simple-callback'  id="boomdevs_1" class="wp-block-heading" >A simple callback</h2>



<p>To get started, let&#8217;s explore a minimal Dash app that features a simple counter and a button to increment its value:</p>



<iframe src="https://scripts.dash-resources.com/callbacks/callbacks1.py/" width="100%" frameBorder="0"></iframe>



<p>The associated code is the following:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import Dash, html, callback, Input, Output, PreventUpdate

app = Dash(__name__)

# Declare the layout
app.layout = html.Div([
    html.P('Count: 0', id='counter'),
    html.Button('Click', id='btn', n_clicks=0)
])

# Define the callback
@app.callback(
    Output('counter', 'children'), 
    Input('btn', 'n_clicks')
)
def update(n_clicks):
    return f"Count: {n_clicks}"

# Run the app
if __name__ == '__main__':
    app.run_server(debug=True)
</code></pre>



<p>The first lines define the app layout. The syntax is highly inspired by HTML elements, but elements are called &#8220;<strong>components</strong>&#8221; in Dash. These components are more than just static elements; they are interactive and seamlessly integrate with Python callbacks to enable dynamic updates.</p>



<pre class="wp-block-code"><code lang="python" class="language-python">app.layout = html.Div([
    html.P('Count: 0', id='counter'),  # same as &lt;p id="counter"&gt;Count: 0&lt;/p&gt; in HTML
    html.Button('Click', id='btn', n_clicks=0)  # same as &lt;button id="btn"&gt;Click&lt;/button&gt; in HTML
])</code></pre>



<p>We explicitly set <code>n_clicks</code> to 0 to initialize the button with a default value. Without this, its value would be <code>None</code>, but the <code>update</code> function is supposed to work with an integer.</p>



<p>The next lines define the callback, which is a core concept in Dash. Dash callbacks are just regular Python functions decorated with the <code>@app.callback</code> decorator (or just <code>@callback</code>). This decorator connects input components (such as button clicks) with output components (like the displayed counter text):</p>



<pre class="wp-block-code"><code lang="python" class="language-python">@app.callback(
    # the parameters are explicitly written now, but usually we don't
    Output(component_id='counter', component_property='children'), 
    Input(component_id='btn', component_property='n_clicks'),
)
def update_counter(n_clicks):
    # ...</code></pre>



<p>Inputs and Outputs must have a specified component ID and property to connect. This makes it clear which actions update the app and what parts of the app are changed. For example, the button&#8217;s <code>n_clicks</code> property triggers the callback, updating the paragraph&#8217;s <code>children</code> property with the new count.</p>



<p class="callout">If you are not familiar with decorators, I suggest you take a look at this tutorial: <a href="https://realpython.com/primer-on-python-decorators/">https://realpython.com/primer-on-python-decorators/</a></p>



<p>Dash callbacks are essential as they enable interactivity. By linking inputs and outputs, they dynamically update the app in response to user actions.</p>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart LR
    btn["Button&lt;br>id='btn2'"] -->|"n_clicks&lt;br>Input"| update_counter(["update&lt;br>callback"])
    update_counter -->|"children&lt;br>Output"| counter["Paragraph&lt;br>id='counter'"]
    style btn fill:#f9f,stroke:#333
    style counter fill:#bbf,stroke:#333
    style update_counter fill:#ff9,stroke:#333
</pre><img decoding="async" src="https://dash-resources.com/wp-content/uploads/2024/12/merpress-3.png" alt=""/></div>



<p>In this example, the counter is incremented each time the button is pressed. The <code>update_counter</code> function encapsulates this logic and returns the result to be updated within the paragraph.</p>



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



<p>Congratulations, you just learned the most essential feature of Dash <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='multi-input-callback'  id="boomdevs_2" class="wp-block-heading" >Multi input callback</h2>



<p>Now, let’s take it a step further. What if you want multiple components to control the same output? Dash makes this possible by supporting multiple inputs in a single callback.</p>



<p>Imagine you have two buttons: one adds 1 for each click, and the other subtracts 1 for each click. </p>



<iframe src="https://scripts.dash-resources.com/callbacks/callbacks2.py/" width="100%" frameBorder="0"></iframe>



<p>Here’s how you can implement it:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">from dash import Dash, html, callback, Input, Output, PreventUpdate

app = Dash(__name__)

# Declare the layout
app.layout = html.Div([
    html.P('Count: 0', id='counter'),
    html.Button('Click +', id='btn_add', n_clicks=0), 
    html.Button('Click -', id='btn_sub', n_clicks=0), # two buttons
])

# Define the callback
@app.callback(
    Output('counter', 'children'), 
    Input('btn_add', 'n_clicks'),
    Input('btn_sub', 'n_clicks') # now we have 2 inputs
)
def update_counter(n_clicks1, n_clicks2):
    return f"Count: {n_clicks1-n_clicks2}"

# Run the app
if __name__ == '__main__':
    app.run_server(debug=True)
</code></pre>



<p>To do so, we simply added an extra Input in our <code>@app.callback</code> decorator. As a result, we now have 2 possible triggers: </p>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart LR
    btn1["Button&lt;br>id='btn_add'"] -->|"n_clicks&lt;br>Input"| update_counter(["update&lt;br>callback"])
    btn2["Button&lt;br>id='btn_sub'"] -->|"n_clicks&lt;br>Input"| update_counter(["update&lt;br>callback"])
    update_counter -->|"children&lt;br>Output"| counter["Paragraph&lt;br>id='counter'"]
    style btn1 fill:#f9f,stroke:#333
    style btn2 fill:#f9f,stroke:#333
    style counter fill:#bbf,stroke:#333
    style update_counter fill:#ff9,stroke:#333
</pre></div>



<p>In some cases, two inputs can be fired at the same time. Dash therefore handles it efficiently by triggering the callback only once. In our example, it means that the counters would update once even if the two buttons are clicked exactly at the same time.</p>



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



<h2 id='multiple-inputs-and-outputs-callbacks'  id="boomdevs_3" class="wp-block-heading" >Multiple inputs and outputs callbacks</h2>



<p>The real excitement begins when we need to update multiple components simultaneously. For example, we can enhance the counter by displaying the result in <span style="color: red;">red</span> if it&#8217;s negative or <span style="color: green;">green</span> if it&#8217;s positive. </p>



<iframe src="https://scripts.dash-resources.com/callbacks/callbacks3.py/" width="100%" frameBorder="0"></iframe>



<p>To achieve this, we update the <code>style</code> property of the component alongside its text. This involves adding another Output in our callback and adjusting the function accordingly:</p>



<pre title="" class="wp-block-code"><code lang="python" class="language-python">@app.callback(
    Output('counter', 'children'), 
    Output('counter', 'style'),  # here we added property "style"
    Input('btn_add', 'n_clicks'),
    Input('btn_sub', 'n_clicks')
)
def update_counter(n_clicks1, n_clicks2):

    content = f"Count: {n_clicks1-n_clicks2}"

    if n_clicks1-n_clicks2 &gt;= 0:
        style = {'color': 'green'}
    else:
        style = {'color': 'red'}

    return content, style  # as a result, we now return two values
</code></pre>



<p>Notice that now the function returns two variables: the content (for <code>children</code> property), and style (for <code>style</code> property). </p>



<p>If inputs can trigger a callback independantly or together, all outputs of a callback are always modified at the exact same time. It means that Dash will always update <code>children</code> and <code>style</code>, whenever the callback is triggered.</p>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart LR
    btn1["Button&lt;br>id='btn_add'"] -->|"n_clicks&lt;br>Input"| update_counter(["update&lt;br>callback"])
    btn2["Button&lt;br>id='btn_sub'"] -->|"n_clicks&lt;br>Input"| update_counter(["update&lt;br>callback"])
    update_counter -->|"children&lt;br>Output"| counter["Paragraph&lt;br>id='counter'"]
    update_counter -->|"style&lt;br>Output"| counter["Paragraph&lt;br>id='counter'"]
    style btn1 fill:#f9f,stroke:#333
    style btn2 fill:#f9f,stroke:#333
    style counter fill:#bbf,stroke:#333
    style update_counter fill:#ff9,stroke:#333
</pre></div>



<p class="callout"><strong>Good to know</strong>: it is still possible to not update an output by providing <code>dash.no_output</code> as value for an output.</p>



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



<h2 id='multiple-callbacks-with-the-same-inputs'  id="boomdevs_4" class="wp-block-heading" >Multiple callbacks with the same inputs</h2>



<p>Dash does not limit the amount of callbacks attached to an input. However, it is theoretically forbidden to have more than one callback per output (= only one callback should be responsible for the update of a component&#8217;s property).</p>



<p class="callout">I wrote &#8216;<em>theoretically</em>&#8216; because it&#8217;s possible with the callback parameter <code>allow_duplicate_output</code>. However, you should avoid using it a much as possible as it makes a code more complicated to debug. See more here: <a href="https://dash.plotly.com/duplicate-callback-outputs">https://dash.plotly.com/duplicate-callback-outputs</a></p>



<p>Let’s add a Progress bar to our counter. We need to update this progress bar every time that the buttons are clicked, hence a new <code>update_pbar</code> callback:</p>



<iframe src="https://scripts.dash-resources.com/callbacks/callbacks4.py/" width="100%" frameBorder="0"></iframe>



<pre class="wp-block-code"><code lang="Python" class="language-Python"># Declare the layout
app.layout = html.Div([
    html.P('Count: 0', id='counter'),
    html.Progress(id="progress_bar", value=0, max=10), # We add the progress bar component
    html.Br(),
    html.Button('Click +', id='btn_add', n_clicks=0),
    html.Button('Click -', id='btn_sub', n_clicks=0),
])

# (... update counter)

@app.callback(
    Output('progress_bar', 'value'), 
    Input('btn_add', 'n_clicks'),
    Input('btn_sub', 'n_clicks')
)
def update_pbar(n_clicks1, n_clicks2):
    # This is a new callback that only updates the progress bar. 
    return n_clicks1-n_clicks2
</code></pre>



<p>As you can see, this callback is simple, only the output is different from the very first callback we implemented. The callback graph might now look like:</p>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart LR
    btn1["Button&lt;br>id='btn_add'"] -->|"n_clicks&lt;br>Input"| update_counter(["update_counter&lt;br>callback"])
    btn2["Button&lt;br>id='btn_sub'"] -->|"n_clicks&lt;br>Input"| update_counter(["update_counter&lt;br>callback"])
    update_counter -->|"children&lt;br>Output"| counter["Paragraph&lt;br>id='counter'"]
    update_counter -->|"style&lt;br>Output"| counter["Paragraph&lt;br>id='counter'"]
    
    btn1["Button&lt;br>id='btn_add'"] -->|"n_clicks&lt;br>Input"| update_pbar(["update_pbar&lt;br>callback"])
    btn2["Button&lt;br>id='btn_sub'"] -->|"n_clicks&lt;br>Input"| update_pbar(["update_pbar&lt;br>callback"])
    update_pbar -->|"value&lt;br>Output"| pbar["Progress&lt;br>id='progress_bar'"]
    
    style btn1 fill:#f9f,stroke:#333
    style btn2 fill:#f9f,stroke:#333
    style counter fill:#bbf,stroke:#333
    style pbar fill:#bbf,stroke:#333
    style update_counter fill:#ff9,stroke:#333
    style update_pbar fill:#ff9,stroke:#333</pre></div>



<p class="callout"><strong>Note</strong>: In this example, we could have updated both the progress bar and the counter in one callback. Whether to group callbacks or keep them separate depends on your app&#8217;s needs. Take a look at this article: <a href="https://dash-resources.com/dash-callbacks-best-practices-with-examples/">Dash Callbacks best practices</a>.</p>



<p>Theorically, these two callbacks should run at the same time. In practice, dash will first trigger on callback and then the second, with no specific order. If you absolutely need one callback to be triggered before the other, then you can chain callbacks (as described in the next section).</p>



<p>True parallel processing is often more complex : it requires having to CPUs (or two servers) running the app. It depends on how the app is deployed, how the server handles the request, etc&#8230;. Most of the time, the callbacks are just run one after the other.</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='chained-callbacks-callbacks-triggering-other-callbacks'  id="boomdevs_5" class="wp-block-heading" >Chained callbacks: callbacks triggering other callbacks</h2>



<p>As your app grows, the logic for updating outputs may depend on multiple interconnected inputs. This is where <strong>chaining callbacks</strong> becomes an invaluable tool. By breaking down complex updates into smaller, linked callbacks, you can maintain a clear and scalable workflow.</p>



<p>Let’s now update our little app and show a multiplier slider. It will multiply the click count with the slider value :</p>



<iframe src="https://scripts.dash-resources.com/callbacks/callbacks5.py/" width="100%" frameBorder="0"></iframe>



<pre class="wp-block-code"><code lang="python" class="language-python"># Declare the layout
app.layout = html.Div([
    html.P('Count: 0', id='counter'),
    html.Progress(id="progress_bar", value=0, max=50),
    html.Br(),
    html.Button('Click +', id='btn_add', n_clicks=0),
    html.Button('Click -', id='btn_sub', n_clicks=0),
    html.Br(),
    html.Label('Multiplier:'),
    dcc.Slider(id='multiplier', min=1, max=5, value=1, step=1)
], style={"max-width": "300px"})

@app.callback(
    Output('counter', 'children'), 
    Output('counter', 'style'), 
    Input('btn_add', 'n_clicks'),
    Input('btn_sub', 'n_clicks'),
    Input('multiplier', 'value')
)
def update_counter(n_clicks1, n_clicks2, multiplier):
    count = (n_clicks1 - n_clicks2) * multiplier
    content = f"Count: {count}"

    if count &gt;= 0:
        style = {'color': 'green'}
    else:
        style = {'color': 'red'}

    return content, style

@app.callback(
    Output('progress_bar', 'value'), 
    Input('btn_add', 'n_clicks'),
    Input('btn_sub', 'n_clicks'),
    Input('multiplier', 'value')
)
def update_pbar(n_clicks1, n_clicks2, multiplier):
    return (n_clicks1 - n_clicks2) * multiplier

</code></pre>



<p>We now have 3 inputs. And this number will increase as the app gets more complex ; and it will get worse when adding more callbacks that use the count result.</p>



<p>A good solution would be to store this count result into memory using a <code>dcc.Store</code> component. The <code>dcc.Store</code> is a special Dash component that allows you to store data in the browser&#8217;s memory &#8211; think of it as a variable that persists between callbacks. It&#8217;s invisible to users but can hold any JSON-serializable data (numbers, strings, lists, or dictionaries). This component is particularly useful for:</p>



<ul class="wp-block-list">
<li>Sharing data between callbacks without passing it through visible components</li>



<li>Reducing the number of redundant calculations</li>



<li>Storing intermediate results that multiple callbacks need to access</li>
</ul>



<p class="callout">Learn more about the <code>dcc.Store</code> component in the official documentation: <a href="https://dash.plotly.com/sharing-data-between-callbacks">https://dash.plotly.com/sharing-data-between-callbacks</a></p>



<p>Here&#8217;s how we can implement it:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">app.layout = html.Div([
    dcc.Store(id='count_memory', data=0),  # Store component to save the count
    # ...
], style={"max-width": "300px"})

@app.callback(
    Output('count_memory', 'data'),  # Update the stored count
    Input('btn_add', 'n_clicks'),
    Input('btn_sub', 'n_clicks'),
    Input('multiplier', 'value'),
    State('count_memory', 'data')  # Access the current stored count
)
def update_store(n_clicks1, n_clicks2, multiplier, current_count):
    count = (n_clicks1 - n_clicks2) * multiplier
    return count

@app.callback(
    Output('counter', 'children'), 
    Output('counter', 'style'), 
    Input('count_memory', 'data')
)
def update_counter_display(count):
    content = f"Count: {count}"
    style = {'color': 'green'} if count &gt;= 0 else {'color': 'red'}
    return content, style

@app.callback(
    Output('progress_bar', 'value'), 
    Input('count_memory', 'data')
)
def update_pbar(count):
    return count
</code></pre>



<p>We now have a callback responsible for the computation (<code>update_store</code>) and two callbacks responsible for display (<code>update_counter_display</code> and <code>update_pbar</code>). This gives the following diagram:</p>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart LR
    btn1["Button&lt;br>id='btn_add'"] -->|"n_clicks&lt;br>Input"| update_store(["update_store&lt;br>callback"])
    btn2["Button&lt;br>id='btn_sub'"] -->|"n_clicks&lt;br>Input"| update_store
    multiplier["Input&lt;br>id='multiplier'"] -->|"value&lt;br>Input"| update_store
    store["Store&lt;br>id='count_memory'"] -.->|"data&lt;br>State"| update_store
    update_store -->|"data&lt;br>Output"| store
    
    store -->|"data&lt;br>Input"| update_counter(["update_counter&lt;br>callback"])
    update_counter -->|"children&lt;br>Output"| counter["Paragraph&lt;br>id='counter'"]
    update_counter -->|"style&lt;br>Output"| counter
    
    store -->|"data&lt;br>Input"| update_pbar(["update_pbar&lt;br>callback"])
    update_pbar -->|"value&lt;br>Output"| pbar["Progress&lt;br>id='progress_bar'"]

    style btn1 fill:#f9f,stroke:#333
    style btn2 fill:#f9f,stroke:#333
    style multiplier fill:#f9f,stroke:#333
    style counter fill:#bbf,stroke:#333
    style pbar fill:#bbf,stroke:#333
    style update_store fill:#ff9,stroke:#333
    style update_counter fill:#ff9,stroke:#333
    style update_pbar fill:#ff9,stroke:#333
    style store fill:#bbf,stroke:#333</pre></div>



<h3 id='using-state-instead-of-input'  id="boomdevs_6" class="wp-block-heading" >Using State instead of Input</h3>



<p>You&#8217;ll notice in our <code>update_store</code> callback that we use <code>State('count_memory', 'data')</code> instead of <code>Input('count_memory', 'data')</code>. This is because we want to access the current stored count but don&#8217;t want changes to it to trigger this callback. If we used Input, we&#8217;d create a <strong>circular dependency</strong>: the store update would trigger the callback, which would update the store, which would trigger the callback again!</p>



<p>Using <code>State</code> allows us to read the stored value only when we need it, while the actual triggers for our callback remain the button clicks and multiplier changes. This pattern of using State to access stored values is common when working with <code>dcc.Store</code> components &#8211; it gives you access to persistent data without creating unintended callback chains.</p>



<p class="callout"><strong>TL;DR</strong>. A <code>State</code> does not trigger a callback while an <code>Input</code> will. But both can be used to retrieve a component&#8217;s property.</p>



<h3 id='advantages-and-disadvantages-of-chaining-callbacks'  id="boomdevs_7" class="wp-block-heading" >Advantages and disadvantages of chaining callbacks</h3>



<p>Chained callbacks help keep your code <strong>clean and logical</strong>. Instead of cramming everything into one big callback, you can break things down into smaller pieces that each do one job well. For example, one callback handles the data processing while another takes care of displaying it. This approach also opens up more interactive possibilities &#8211; when one callback&#8217;s output feeds into another&#8217;s input, you can create complex interactions like filters that update charts, which then update summary statistics.</p>



<p>But there are some <strong>pitfalls</strong> to be careful about. <strong>Debugging can get tricky</strong> when you have callback A triggering B, which triggers C and D, which then trigger even more callbacks&#8230; well, good luck figuring out where something went wrong!</p>



<p>You should also watch out for <strong>circular dependencies</strong> &#8211; that&#8217;s when your callbacks form a loop (A triggers B triggers C triggers A again). Dash will catch this and throw an error, but it&#8217;s a common gotcha when you&#8217;re building complex apps.</p>



<p class="callout">Want to learn more about avoiding circular dependencies? We have a full article here: <a href="https://dash-resources.com/writing-in-process/?article=avoid-circular-dependancies">How to avoid circular dependancies problem in Dash Plotly</a></p>



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



<h2 id='other-types-of-callbacks'  id="boomdevs_8" class="wp-block-heading" >Other types of callbacks</h2>



<p>While we&#8217;ve covered the main callback patterns, Dash offers several specialized types of callbacks for specific use cases:</p>



<h3 id='background-callbacks'  id="boomdevs_9" class="wp-block-heading" >Background Callbacks</h3>



<p>Background callbacks handle time-consuming operations without blocking your app&#8217;s responsiveness. They run intensive tasks in separate threads, making them perfect for heavy computations or long-running processes:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">@app.callback(
    Output("results", "children"),
    Input("start", "n_clicks"),
    background=True
)
def slow_computation(n_clicks):
    # Your heavy computation here
    time.sleep(5)  # Simulating long task
    return "Done!"</code></pre>



<p>Learn more in our guide: <a href="https://dash-resources.com/writing-in-process/?article=how to use bavkground callbacks in dash plotly">How to Use Background Callbacks in Dash Plotly</a></p>



<h3 id='clientside-callbacks'  id="boomdevs_10" class="wp-block-heading" >Clientside Callbacks</h3>



<p>Clientside callbacks execute <strong>directly in the browser</strong>, eliminating server round-trips for faster performance. They&#8217;re ideal for simple UI updates and responsive interactions, but require JavaScript:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">app.clientside_callback(
    """
    function(value) {
        return 'You typed: ' + value
    }
    """,
    Output('output-div', 'children'),
    Input('input-box', 'value')
)</code></pre>



<p>Learn more: <a href="https://dash-resources.com/writing-in-process/?article=when to use clientside calbacks for dash plotly">When to use clientside callbacks for Dash Plotly</a>.</p>



<h3 id='pattern-matching-callbacks'  id="boomdevs_11" class="wp-block-heading" >Pattern-Matching Callbacks</h3>



<p>Pattern-matching callbacks enable handling dynamic sets of components through ID patterns. They&#8217;re particularly useful to attach callbacks to components that are created or removed at runtime:</p>



<pre class="wp-block-code"><code lang="python" class="language-python">@app.callback(
    Output({'type': 'dynamic-output', 'index': MATCH}, 'children'),
    Input({'type': 'dynamic-input', 'index': MATCH}, 'value')
)
def update_dynamic_output(value):
    return f"You entered: {value}"</code></pre>



<p>Read the guide: <a href="https://dash-resources.com/writing-in-process/?article=pattern-matching-callbacks">How to use Pattern Matching Callbacks (Dash Plotly)</a>.</p>



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



<p>In this article, we explored the main types of Dash callbacks, from simple callbacks to multi-input, multi-output, and chained callbacks.</p>



<p>To deepen your understanding of Dash callbacks, you can:</p>



<ul class="wp-block-list">
<li><strong>Read the <a href="https://dash.plotly.com/basic-callbacks">official documentation</a> on Dash callbacks:</strong> it’s dense, but there are much more detailed information than in this article (which was focused on giving simple examples).</li>



<li><strong>Play with the toy examples above:</strong> you could add more inputs, change the computation, add other types of components… be creative! It’s the best to learn.</li>



<li><strong>Go deeper with other types of callbacks</strong>: you now have the fundation for understand how callbacks triggered. Learn how to use background callbacks, clientside callbacks and patter-matching callbacks.</li>
</ul>



<p>I hope you enjoyed this tutorial! <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>



<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></p>
<p>L’article <a href="https://dash-resources.com/tutorial-dash-callbacks-schemas-examples/">Tutorial: Dash callbacks (schemas &amp; examples)</a> est apparu en premier sur <a href="https://dash-resources.com">dash-resources.com</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
