Browser page loading too slow, after adding many callbacks

I am trying to build a complex admin panel with a lot of pages, using dash.
I am using dash’s dynamic layout to load the multi-page environment.

After adding in my app 10 callbacks with 10-20 inputs/states and 10-30 outputs each, the initial page load takes about 2 seconds.
If I increase the number of callbacks to 100, just to stress test the plotly dash, the browser takes around 90 seconds to load.
If I continue the development that way, my app will be practically unusable after some more pages implementation.

As I can guess, dash tries to pre-load and prepare all of the callbacks when the page loads, no matter if the user will need them in the current page.
Is there something I can do to make that perform better or it is just a limitation of the current version (running 1.12) of dash?
Perhaps sending to the browser only the callbacks that every page needs… But I can’t find such an option in dash documentation…

Thank you!

The actual callback definitions aren’t very large so the network cost is relatively small. It’s more inefficiencies in dash’s code when you add hundreds of callbacks. We plan on speeding things up for this use case eventually. In the meantime, apps that have hundreds of callbacks frequently can use the (new!) pattern matching callback pattern, which will speed things up and improve your code (no longer need to generate callbacks dynamically): https://dash.plotly.com/pattern-matching-callbacks

I am already using the new pattern matching callback pattern, it really helps indeed!
All these numbers I am giving you are the bare minimum for my app, I can’t find a way to use less, because there are so many different components in it and of course every component has it own special properties that I can’t use pattern matching.
So unfortunately, I guess that dash can’t match the requirements of my app at the current version.

Anyway, it is good to hear that there are plans for optimizations!
Is it a work in progress? Do you track those updates in a branch in your github?

Thank you for your reply!

there isn’t any work in progress right now for this use case, but we are working on some code to improve the performance when there are many elements on the page, which may help your use case. This is the PR for that work: https://github.com/plotly/dash/pull/1254

Performance optimization is a long and deep rabbit hole, so this is work that may wait until enough Dash Enterprise customers request it or an organization with a software budget fund its development: https://plotly.com/products/consulting-and-oem

1 Like

Do you need to keep everything in one app? Otherwise, you might be able to speed up the initial load by splitting the code into multiple apps.

This is a temporary workaround that worth a shot. I could try to split the admin panel with the user panel via two separated dash apps and a flask route for each one of them. But it is only here for the short-term. When the app will grow, the problem will be still there.
Thanks for the advice.

The prevent_initial_call keyword argument for callbacks was added in Dash v1.12.0. Set this argument to True for all of your pattern matching callbacks (or any callbacks that don’t need to fire when the page loads) to prevent them all from sending requests to the server and waiting for responses at the same time.

Here’s an example of the prevent_initial_call keyword argument.

@app.callback(
    Output({"type": "content_task", "id": MATCH}, "is_open"),
    Input({"type": "form_task", "id": MATCH}, "is_open"),
    prevent_initial_call=True
)
def update_content_task(form_is_open):
    return not form_is_open
1 Like

I’ve been trying to research this more, have there been any updates?

I have an app with about 150 callbacks and currently on page refresh or navigation to new pages it takes about 5-10 seconds to load the page (ie. “Loading” displayed at the top right corner). Is this typical?

Hello @mworth,

Welcome to the community!

When you say navigating to new pages, how are you doing it? When using pages it shouldn’t reload the whole app. It sounds like your links are wrong if so.

Also, if you need to, you can look into my page caching. :grin:

Hey, thank you! That’s honestly what I was hoping, that I just had a bad configuration or setup somewhere.

I’m using pages right now, and now that I think about it… I remember coding this a long time ago…

link = dcc.Link(
                label,
                href=f'/auth/{href_path}',  # The relative href structure based on the original file tree string
                refresh=True
            )

Which explains why navigating to new pages is slow. But my concern now is still on loading times. Should 150 callbacks take 5-10 seconds for the page to load on initial visit or refresh?

Refresh should be left alone, refresh True means it reloads the entire layout upon navigation, instead of just using a POST request to populate the page’s data.

As far as the page taking a while to load initially, there is quite a ton of things that need to load the first time a user visits, you can decrease successive loads by allowing the users browser to cache things in the /_dash-components-suites path.

Interesting, could you point me in the right direction for how to allow a users browser to cache the /_dash-components-suites path?

For this, you will need to have something like a load balancer in place. Like nginx for Linux.

Then you set up caching on it for a good while, enough that successive calls to the app will load quicker.