Dash Production Dashboard Skill
Build enterprise-grade interactive dashboards with Plotly Dash. Features reactive callbacks, professional layouts, and scalable deployment for production workloads.
When to Use This Skill
USE Dash when:
- Production dashboards - Building dashboards for business users
- Complex interactivity - Need fine-grained control over updates
- Enterprise requirements - Authentication, scaling, reliability needed
- Plotly ecosystem - Already using Plotly for visualizations
- Custom components - Need to extend with JavaScript/React
- Long-term projects - Dashboard will be maintained and extended
- Multi-user access - Multiple concurrent users accessing dashboards
DON'T USE Dash when:
- Quick prototypes - Use Streamlit for faster iteration
- Simple visualizations - Static reports may suffice
- No interactivity needed - Use static HTML/PDF reports
- Limited Python knowledge - Steeper learning curve than Streamlit
- Single-user tools - Jupyter notebooks may be simpler
Prerequisites
pip install dash
pip install dash plotly pandas dash-bootstrap-components
pip install dash plotly pandas polars dash-bootstrap-components dash-ag-grid gunicorn
uv pip install dash plotly pandas dash-bootstrap-components dash-ag-grid
Core Capabilities
1. Basic Application Structure
Minimal Dash App:
from dash import Dash, html, dcc
import plotly.express as px
import pandas as pd
app = Dash(__name__)
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "NYC", "NYC", "NYC"]
})
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
app.layout = html.Div([
html.H1("Hello Dash"),
html.P("This is a simple Dash application."),
dcc.Graph(id="example-graph", figure=fig)
])
if __name__ == "__main__":
app.run(debug=True)
Run the app:
python app.py
2. Callbacks and Interactivity
Basic Callback:
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd
app = Dash(__name__)
df = pd.DataFrame({
"date": pd.date_range("2025-01-01", periods=100),
"category": ["A", "B", "C", "D"] * 25,
"value": range(100)
})
app.layout = html.Div([
html.H1("Interactive Dashboard"),
html.Label("Select Category:"),
dcc.Dropdown(
id="category-dropdown",
options=[{"label": c, "value": c} for c in df["category"].unique()],
value="A",
clearable=False
),
dcc.Graph(id="line-chart")
])
@callback(
Output("line-chart", "figure"),
Input("category-dropdown", "value")
)
def update_chart(selected_category):
filtered_df = df[df["category"] == selected_category]
fig = px.line(
filtered_df,
x="date",
y="value",
title=
)
fig
__name__ == :
app.run(debug=)
Multiple Inputs and Outputs:
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd
app = Dash(__name__)
df = pd.DataFrame({
"date": pd.date_range("2025-01-01", periods=365),
"category": ["A", "B", "C"] * 122 + ["A"],
"region": ["North", "South", "East", "West"] * 91 + ["North"],
"value": [i + (i % 30) * 10 for i in range(365)]
})
app.layout = html.Div([
html.H1("Multi-Input Dashboard"),
html.Div([
html.Div([
html.Label("Category"),
dcc.Dropdown(
id="category-filter",
options=[{"label": c, "value": c} for c in df["category"].unique()],
value=["A", "B", "C"],
multi=True
)
], style={"width": "45%", "display": "inline-block"}),
html.Div([
html.Label("Region"),
dcc.Dropdown(
=,
options=[{: r, : r} r df[].unique()],
value=[, , , ],
multi=
)
], style={: , : , : })
]),
html.Div([
html.Div([
dcc.Graph(=)
], style={: , : }),
html.Div([
dcc.Graph(=)
], style={: , : , : })
]),
html.Div(=)
])
():
filtered = df[
(df[].isin(categories)) &
(df[].isin(regions))
]
trend = filtered.groupby()[].().reset_index()
trend_fig = px.line(trend, x=, y=, title=)
by_category = filtered.groupby()[].().reset_index()
pie_fig = px.pie(by_category, values=, names=, title=)
stats = html.Div([
html.H4(),
html.P(),
html.P(),
html.P()
])
trend_fig, pie_fig, stats
__name__ == :
app.run(debug=)
Chained Callbacks:
from dash import Dash, html, dcc, callback, Output, Input
import pandas as pd
app = Dash(__name__)
data = {
"USA": {"California": ["San Francisco", "Los Angeles"], "Texas": ["Houston", "Dallas"]},
"Canada": {"Ontario": ["Toronto", "Ottawa"], "Quebec": ["Montreal", "Quebec City"]}
}
app.layout = html.Div([
html.H1("Chained Dropdowns"),
html.Label("Country"),
dcc.Dropdown(id="country-dropdown"),
html.Label("State/Province"),
dcc.Dropdown(id="state-dropdown"),
html.Label("City"),
dcc.Dropdown(id="city-dropdown"),
html.Div(id="selection-output")
])
@callback(
Output("country-dropdown", "options"),
Input("country-dropdown", "id")
)
def set_countries(_):
return [{"label": c, "value": c} for c in data.keys()]
():
country :
[],
states = data.get(country, {}).keys()
[{: s, : s} s states],
():
country state :
[],
cities = data.get(country, {}).get(state, [])
[{: c, : c} c cities],
():
__name__ == :
app.run(debug=)
3. Layout Components
HTML Components:
from dash import html
layout = html.Div([
html.H1("Main Title"),
html.H2("Subtitle"),
html.H3("Section Header"),
html.P("Paragraph text with ", html.Strong("bold"), " and ", html.Em("italic")),
html.Hr(),
html.Br(),
html.Ul([
html.Li("Item 1"),
html.Li("Item 2"),
html.Li("Item 3")
]),
html.A("Click here", href="https://example.com", target="_blank"),
html.Img(src="/assets/logo.png", style={"width": "200px"}),
html.Table([
html.Thead([
html.Tr([html.Th("Name"), html.Th("Value")])
]),
html.Tbody([
html.Tr([html.Td("Item 1"), html.Td("100")]),
html.Tr([html.Td("Item 2"), html.Td("200")])
])
])
])
Core Components (dcc):
from dash import dcc
components = html.Div([
dcc.Dropdown(
id="dropdown",
options=[
{"label": "Option A", "value": "a"},
{"label": "Option B", "value": "b"},
{"label": "Option C", "value": "c", "disabled": True}
],
value="a",
multi=False,
clearable=True,
searchable=True,
placeholder="Select..."
),
dcc.Dropdown(
id="multi-dropdown",
options=[{"label": f"Option {i}", "value": i} for i in range(10)],
value=[1, 2, 3],
multi=True
),
dcc.Slider(
id="slider",
min=0,
max=100,
step=5,
value=50,
marks={0: , : , : , : , : }
),
dcc.RangeSlider(
=,
=,
=,
step=,
value=[, ],
marks={i: (i) i (, , )}
),
dcc.Input(
=,
=,
placeholder=,
debounce=
),
dcc.Textarea(
=,
placeholder=,
style={: , : }
),
dcc.Checklist(
=,
options=[
{: , : },
{: , : },
{: , : }
],
value=[],
inline=
),
dcc.RadioItems(
=,
options=[
{: , : },
{: , : },
{: , : }
],
value=,
inline=
),
dcc.DatePickerSingle(
=,
date=,
display_format=
),
dcc.DatePickerRange(
=,
start_date=,
end_date=,
display_format=
),
dcc.Upload(
=,
children=html.Div([, html.A()]),
style={
: ,
: ,
: ,
: ,
: ,
: ,
:
}
),
dcc.Tabs(=, value=, children=[
dcc.Tab(label=, value=),
dcc.Tab(label=, value=)
]),
dcc.Loading(
=,
=,
children=html.Div(=)
),
dcc.Interval(
=,
interval=,
n_intervals=
),
dcc.Store(=, storage_type=),
dcc.Graph(
=,
config={
: ,
: ,
: [, ]
}
)
])
4. Bootstrap Components
Using Dash Bootstrap Components:
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
df = pd.DataFrame({
"date": pd.date_range("2025-01-01", periods=100),
"sales": [100 + i * 2 + (i % 7) * 10 for i in range(100)],
"orders": [50 + i + (i % 5) * 5 for i in range(100)]
})
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
html.H1("Sales Dashboard", className="text-primary"),
html.P("Interactive analytics powered by Dash", className="lead")
])
], className="mb-4"),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4("Total Sales", className="card-title"),
html.H2(f"${df['sales'].sum():,}", className="text-success")
])
])
], md=),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4(, className=),
html.H2(, className=)
])
])
], md=),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4(, className=),
html.H2(, className=)
])
])
], md=)
], className=),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardHeader(),
dbc.CardBody([
dbc.Label(),
dcc.DatePickerRange(
=,
start_date=df[].(),
end_date=df[].(),
className=
),
dbc.Label(),
dcc.Dropdown(
=,
options=[
{: , : },
{: , : }
],
value=
)
])
])
], md=),
dbc.Col([
dcc.Graph(=)
], md=)
]),
dbc.Row([
dbc.Col([
dbc.Tabs([
dbc.Tab(label=, tab_id=),
dbc.Tab(label=, tab_id=)
], =, active_tab=),
html.Div(=, className=)
])
], className=)
], fluid=)
():
filtered = df[
(df[] >= start_date) &
(df[] <= end_date)
]
fig = px.line(
filtered,
x=,
y=metric,
title=
)
fig.update_layout(template=)
fig
():
tab == :
dbc.Table.from_dataframe(
df.tail(),
striped=,
bordered=,
hover=
)
tab == :
html.Div([
html.P(),
html.P(),
html.P()
])
__name__ == :
app.run(debug=)
5. Multi-Page Applications
Project Structure:
my_dash_app/
├── app.py # Main entry point
├── pages/
│ ├── __init__.py
│ ├── home.py
│ ├── analytics.py
│ └── settings.py
├── components/
│ ├── __init__.py
│ ├── navbar.py
│ └── footer.py
├── utils/
│ ├── __init__.py
│ └── data.py
└── assets/
├── style.css
└── logo.png
Main App (app.py):
from dash import Dash, html, dcc, page_container
import dash_bootstrap_components as dbc
app = Dash(
__name__,
use_pages=True,
external_stylesheets=[dbc.themes.BOOTSTRAP]
)
navbar = dbc.NavbarSimple(
children=[
dbc.NavItem(dbc.NavLink("Home", href="/")),
dbc.NavItem(dbc.NavLink("Analytics", href="/analytics")),
dbc.NavItem(dbc.NavLink("Settings", href="/settings")),
],
brand="My Dashboard",
brand_href="/",
color="primary",
dark=True,
)
app.layout = html.Div([
navbar,
dbc.Container([
page_container
], fluid=True, className="mt-4")
])
if __name__ == "__main__":
app.run(debug=True)
Home Page (pages/home.py):
from dash import html, register_page
import dash_bootstrap_components as dbc
register_page(__name__, path="/", name="Home")
layout = dbc.Container([
dbc.Row([
dbc.Col([
html.H1("Welcome to the Dashboard"),
html.P("Select a page from the navigation bar to get started."),
dbc.Card([
dbc.CardBody([
html.H4("Quick Links"),
dbc.ListGroup([
dbc.ListGroupItem("Analytics", href="/analytics"),
dbc.ListGroupItem("Settings", href="/settings")
])
])
])
])
])
])
Analytics Page (pages/analytics.py):
from dash import html, dcc, callback, Output, Input, register_page
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
register_page(__name__, path="/analytics", name="Analytics")
df = pd.DataFrame({
"date": pd.date_range("2025-01-01", periods=365),
"value": [100 + i + (i % 30) * 5 for i in range(365)]
})
layout = dbc.Container([
html.H1("Analytics"),
dbc.Row([
dbc.Col([
dbc.Label("Chart Type"),
dcc.Dropdown(
id="chart-type",
options=[
{"label": "Line", "value": "line"},
{"label": "Bar", "value": "bar"},
{"label": "Area", "value": "area"}
],
value="line"
)
], md=4)
], className="mb-4"),
dcc.Graph(id="analytics-chart")
])
@callback(
Output("analytics-chart", ),
Input()
)
():
chart_type == :
fig = px.line(df, x=, y=)
chart_type == :
monthly = df.resample(, on=)[].().reset_index()
fig = px.bar(monthly, x=, y=)
:
fig = px.area(df, x=, y=)
fig
6. Authentication
Basic Authentication:
from dash import Dash, html, dcc
import dash_auth
app = Dash(__name__)
VALID_USERNAME_PASSWORD_PAIRS = {
"admin": "admin123",
"user": "user123"
}
auth = dash_auth.BasicAuth(
app,
VALID_USERNAME_PASSWORD_PAIRS
)
app.layout = html.Div([
html.H1("Protected Dashboard"),
html.P("You are authenticated!")
])
if __name__ == "__main__":
app.run(debug=True)
Custom Login (with session):
from dash import Dash, html, dcc, callback, Output, Input, State
import dash_bootstrap_components as dbc
from flask import session
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.server.secret_key = "your-secret-key-here"
login_form = dbc.Card([
dbc.CardBody([
html.H4("Login"),
dbc.Input(id="username", placeholder="Username", className="mb-2"),
dbc.Input(id="password", type="password", placeholder="Password", className="mb-2"),
dbc.Button("Login", id="login-btn", color="primary"),
html.Div(id="login-message")
])
], style={"maxWidth": "400px", "margin": "100px auto"})
main_content = html.Div([
html.H1("Dashboard"),
html.P("Welcome! You are logged in."),
dbc.Button("Logout", id="logout-btn", color="secondary")
])
app.layout = html.Div([
dcc.Location(id="url"),
html.Div(id="page-content")
])
@callback(
Output("page-content", "children"),
Input(, )
)
():
session.get():
main_content
login_form
():
username == password == :
session[] =
,
dbc.Alert(, color=),
():
session.clear()
__name__ == :
app.run(debug=)
Complete Examples
Example 1: Sales Analytics Dashboard
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
app = Dash(__name__, external_stylesheets=[dbc.themes.FLATLY])
np.random.seed(42)
dates = pd.date_range("2024-01-01", "2025-12-31", freq="D")
n_days = len(dates)
df = pd.DataFrame({
"date": dates,
"revenue": np.cumsum(np.random.randn(n_days) * 100 + 500),
"orders": np.random.poisson(100, n_days),
"customers": np.random.poisson(80, n_days),
"region": np.random.choice(["North", "South", "East", "West"], n_days),
"category": np.random.choice(["Electronics", "Clothing", "Food", "Home"], n_days)
})
current_revenue = df[df["date"] >= "2025-01-01"]["revenue"].sum()
prev_revenue = df[df[] < ][].()
revenue_change = ((current_revenue - prev_revenue) / prev_revenue * )
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
html.H1(, className=),
html.P(, className=)
], md=),
dbc.Col([
dbc.ButtonGroup([
dbc.Button(, outline=, color=),
dbc.Button(, outline=, color=)
])
], md=, className=)
], className=),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
dbc.Row([
dbc.Col([
dbc.Label(),
dcc.DatePickerRange(
=,
start_date=,
end_date=,
display_format=
)
], md=),
dbc.Col([
dbc.Label(),
dcc.Dropdown(
=,
options=[{: r, : r} r df[].unique()],
value=df[].unique().tolist(),
multi=
)
], md=),
dbc.Col([
dbc.Label(),
dcc.Dropdown(
=,
options=[{: c, : c} c df[].unique()],
value=df[].unique().tolist(),
multi=
)
], md=)
])
])
])
])
], className=),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H6(, className=),
html.H3(=, className=),
html.Small(=, className=)
])
], color=)
], md=),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H6(, className=),
html.H3(=, className=),
html.Small(=, className=)
])
], color=)
], md=),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H6(, className=),
html.H3(=, className=),
html.Small(=, className=)
])
], color=)
], md=),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H6(, className=),
html.H3(=, className=),
html.Small(=, className=)
])
], color=)
], md=)
], className=),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardHeader(),
dbc.CardBody([
dcc.Graph(=)
])
])
], md=),
dbc.Col([
dbc.Card([
dbc.CardHeader(),
dbc.CardBody([
dcc.Graph(=)
])
])
], md=)
], className=),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardHeader(),
dbc.CardBody([
dcc.Graph(=)
])
])
], md=),
dbc.Col([
dbc.Card([
dbc.CardHeader(),
dbc.CardBody([
dcc.Graph(=)
])
])
], md=)
], className=),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardHeader(),
dbc.CardBody([
html.Div(=)
])
])
])
])
], fluid=)
():
filtered = df[
(df[] >= start_date) &
(df[] <= end_date) &
(df[].isin(regions)) &
(df[].isin(categories))
]
revenue =
orders =
customers =
aov = filtered[].() >
daily_revenue = filtered.groupby()[].().reset_index()
trend_fig = px.line(
daily_revenue,
x=,
y=,
title=
)
trend_fig.update_layout(
margin=(l=, r=, t=, b=),
hovermode=
)
by_category = filtered.groupby()[].().reset_index()
pie_fig = px.pie(
by_category,
values=,
names=,
title=
)
pie_fig.update_layout(margin=(l=, r=, t=, b=))
by_region = filtered.groupby().agg({
: ,
:
}).reset_index()
bar_fig = px.bar(
by_region,
x=,
y=,
color=,
title=
)
bar_fig.update_layout(
margin=(l=, r=, t=, b=),
showlegend=
)
scatter_fig = px.scatter(
filtered.groupby().agg({: , : }).reset_index(),
x=,
y=,
title=,
trendline=
)
scatter_fig.update_layout(margin=(l=, r=, t=, b=))
table = dbc.Table.from_dataframe(
filtered.groupby([, ]).agg({
: ,
: ,
:
}).reset_index().(),
striped=,
bordered=,
hover=,
responsive=
)
revenue, orders, customers, aov, trend_fig, pie_fig, bar_fig, scatter_fig, table
__name__ == :
app.run(debug=)
Example 2: Real-Time Monitoring Dashboard
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
from collections import deque
import random
from datetime import datetime
app = Dash(__name__, external_stylesheets=[dbc.themes.CYBORG])
MAX_POINTS = 50
time_data = deque(maxlen=MAX_POINTS)
cpu_data = deque(maxlen=MAX_POINTS)
memory_data = deque(maxlen=MAX_POINTS)
network_data = deque(maxlen=MAX_POINTS)
app.layout = dbc.Container([
html.H1("Real-Time System Monitor", className="text-center my-4"),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H6("CPU Usage"),
html.H2(id="cpu-value", className="text-info"),
dbc.Progress(id="cpu-progress", value=0, max=100)
])
])
], md=4),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H6("Memory Usage"),
html.H2(id="memory-value", className="text-warning"),
dbc.Progress(id="memory-progress", value=0, max=100)
])
])
], md=4),
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H6("Network I/O"),
html.H2(=, className=),
dbc.Progress(=, value=, =)
])
])
], md=)
], className=),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardHeader(),
dbc.CardBody([
dcc.Graph(=, animate=)
])
])
])
]),
dcc.Interval(
=,
interval=,
n_intervals=
)
], fluid=)
():
cpu = random.uniform(, )
memory = random.uniform(, )
network = random.uniform(, )
time_data.append(datetime.now())
cpu_data.append(cpu)
memory_data.append(memory)
network_data.append(network)
fig = go.Figure()
fig.add_trace(go.Scatter(
x=(time_data),
y=(cpu_data),
name=,
mode=,
line=(color=)
))
fig.add_trace(go.Scatter(
x=(time_data),
y=(memory_data),
name=,
mode=,
line=(color=)
))
fig.add_trace(go.Scatter(
x=(time_data),
y=(network_data),
name=,
mode=,
line=(color=)
))
fig.update_layout(
template=,
paper_bgcolor=,
plot_bgcolor=,
yaxis=(=[, ], title=),
xaxis=(title=),
legend=(orientation=, yanchor=, y=),
margin=(l=, r=, t=, b=),
uirevision=
)
(
,
,
,
cpu,
memory,
network,
fig
)
__name__ == :
app.run(debug=)
Example 3: Data Table with AG Grid
from dash import Dash, html, callback, Output, Input
import dash_ag_grid as dag
import dash_bootstrap_components as dbc
import pandas as pd
import numpy as np
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
np.random.seed(42)
df = pd.DataFrame({
"ID": range(1, 1001),
"Name": [f"Product {i}" for i in range(1, 1001)],
"Category": np.random.choice(["Electronics", "Clothing", "Food", "Home"], 1000),
"Price": np.random.uniform(10, 500, 1000).round(2),
"Stock": np.random.randint(0, 100, 1000),
"Rating": np.random.uniform(1, 5, 1000).round(1),
"Last Updated": pd.date_range("2025-01-01", periods=1000, freq="H")
})
column_defs = [
{"field": , : , : },
{: , : },
{
: ,
: ,
: {: }
},
{
: ,
: ,
: {: },
: {
:
}
},
{
: ,
: ,
: {
:
}
},
{
: ,
: ,
: ,
: {
: {
: ,
:
}
}
},
{
: ,
: ,
: {: }
}
]
app.layout = dbc.Container([
html.H1(, className=),
dbc.Row([
dbc.Col([
dbc.Input(
=,
placeholder=,
className=
)
], md=),
dbc.Col([
dbc.Button(, =, color=)
], md=)
]),
dag.AgGrid(
=,
columnDefs=column_defs,
rowData=df.to_dict(),
defaultColDef={
: ,
: ,
: ,
:
},
dashGridOptions={
: ,
: ,
: ,
:
},
style={: }
),
html.Div(=, className=)
], fluid=)
():
{
: ,
: ,
: ,
: ,
: search_value
}
():
selected:
dbc.Alert(
,
color=
)
__name__ == :
app.run(debug=)
Deployment Patterns
Gunicorn Production Server
from app import app
server = app.server
if __name__ == "__main__":
server.run()
gunicorn wsgi:server -b 0.0.0.0:8050 -w 4
Docker Deployment
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8050
CMD ["gunicorn", "wsgi:server", "-b", "0.0.0.0:8050", "-w", "4"]
version: "3.8"
services:
dash:
build: .
ports:
- "8050:8050"
environment:
- DASH_DEBUG=false
restart: unless-stopped
Cloud Deployment (Heroku)
# Procfile
web: gunicorn wsgi:server
# requirements.txt
dash>=2.14.0
dash-bootstrap-components>=1.5.0
plotly>=5.18.0
pandas>=2.0.0
gunicorn>=21.0.0
Best Practices
1. Optimize Callback Performance
@callback(
Output("output", "children"),
Input("button", "n_clicks"),
prevent_initial_call=True
)
def handle_click(n_clicks):
return f"Clicked {n_clicks} times"
@callback(
Output("output", "children"),
Input("submit-btn", "n_clicks"),
State("input-field", "value")
)
def submit_form(n_clicks, value):
return f"Submitted: {value}"
2. Efficient Data Loading
from flask_caching import Cache
cache = Cache(app.server, config={"CACHE_TYPE": "simple"})
@cache.memoize(timeout=300)
def load_data():
return pd.read_parquet("large_file.parquet")
3. Modular Callbacks
from dash import callback, Output, Input
def register_callbacks(app):
@callback(
Output("chart", "figure"),
Input("dropdown", "value")
)
def update_chart(value):
return create_figure(value)
4. Error Handling
from dash import callback, Output, Input
from dash.exceptions import PreventUpdate
@callback(
Output("output", "children"),
Input("input", "value")
)
def safe_callback(value):
if value is None:
raise PreventUpdate
try:
result = process(value)
return result
except Exception as e:
return html.Div(f"Error: {str(e)}", className="text-danger")
Troubleshooting
Common Issues
Issue: Callback not firing
Issue: Slow initial load
dcc.Loading(
children=[dcc.Graph(id="graph")],
type="circle"
)
Issue: Memory leaks
Issue: Multiple callback outputs
@callback(
Output("output", "children", allow_duplicate=True),
Input("button2", "n_clicks"),
prevent_initial_call=True
)
Version History
- 1.0.0 (2026-01-17): Initial release
- Core application structure
- Callbacks and interactivity
- Layout components (HTML, DCC, Bootstrap)
- Multi-page applications
- Authentication patterns
- Complete dashboard examples
- Real-time monitoring example
- AG Grid integration
- Deployment patterns
- Best practices and troubleshooting
Resources
Build enterprise-grade interactive dashboards with Python and Plotly!