AI coding assistants (also known as AI agents) that integrate with tools such as Cursor, GitHub Copilot, Codex, and Claude Code can accelerate your Dash development workflow. Dash’s declarative, component-based layout means an AI assistant can generate data applications without juggling separate frontend and backend codebases. Combined with Plotly’s expressive charting API, AI assistants can quickly go from a natural-language prompt to a polished, interactive dashboard.
This guide covers how to configure popular AI assistants for optimal Dash development, including recommended project configuration files you can paste directly into your project files.
There are two items you can set up to help get your AI environment up and running. We recommend using them in this order.
If you use an IDE or tool with an integrated AI agent (such as Cursor, Windsurf, Claude Code, or Claude Desktop), you can connect it directly to the Dash docs MCP server. This integration allows any MCP-compatible agent to seamlessly browse, search, and read the entire Dash documentation right from your development environment. You don’t need to specify which tool to use; simply ask your question, and the agent will automatically pull the relevant API details and chart specs. This significantly reduces LLM hallucinations and ensures your AI always relies on the most up-to-date documentation.
AGENTS.md is a file that is automatically fed into your prompts as system context to guide the agent. It defines your project’s architecture, tech stack, and goals upfront, ensuring the AI aligns with your codebase standards from the very first interaction without repetitive prompting. A base AGENTS.md file is provided for you below; you can tweak it to better suit your needs.
Provide sample data: Include example data structures or attach sample CSVs so the AI can generate appropriate visualizations.
Describe callback relationships: For complex apps, explain how callbacks should chain together.
Include your requirements.txt: Paste or reference your existing dependencies so the AI doesn’t introduce conflicting packages or miss what’s already available.
Iterate visually: Run the app after each change. Describe what you see and what you want done differently. AI assistants respond well to feedback like “make the sidebar narrower” or “add a loading spinner to the graph”.
Specify your target: Mention if you’re publishing to Plotly Cloud or Dash Enterprise (the required files and workflow differ). More on this below.
Specify your libraries: Specify which component libraries you would like the agent to use. An example is provided in the sample AGENTS.md
An AGENTS.md file in your project root helps AI assistants understand your project conventions and your publishing target. Some tools use different names for this file, so the easiest way to set this up is to copy the relevant configuration below and paste it directly into your AI assistant’s chat. Ask it to save the configuration either globally or for your specific project. Adapt the file by keeping only what you need. The following configuration includes guidance for both publishing targets and project setups for a wide range of use cases.
## File Structure
my-dash-app/
├── app.py # Main application file
├── assets/ # Static files (CSS, images, favicon)
├── pages/ # Directory for multi-page app routes
└── home.py
└── analytics.py
├── requirements.txt # Python dependencies
└── AGENTS.md # This file
If deploying to Dash Enterprise, also add:
├── Procfile # Process declarations (required)
├── project.toml # Build configuration (optional)
└── Aptfile # System packages (optional)
If deploying to Plotly Cloud, also add:
└── plotly-cloud.toml # Build configuration (optional)
## General Architecture
- **Global Variables**: Never use global variables to store user-specific state. All mutable state must live in the client browser using `dcc.Store` or URL parameters.
- **Server Variable**: Make sure the app file always exposes a server variable: `server = app.server`
- **Dash Pages**: If Snapshot Engine is used, do not use Dash Pages; use callback routing instead to navigate between views. Otherwise, use `dash.page_registry`, keep all pages in a `pages/` directory, and register each page with `dash.register_page(__name__)`.
- **App IDs**: Prefer descriptive IDs like `"sales-filter-dropdown"` over `"dropdown-1"`. IDs must be unique across the entire app, including all pages.
- **Loading Data**: Load data inside callbacks, not at import time. Avoid `df = pd.read_csv(...)` at module level. Data loaded at startup won't refresh until the process restarts. Fetch or refresh data inside the callback that needs it, or use a layout function (`def serve_layout(): ...`) when the layout must be rebuilt on each page load.
- **Server-side Filtering**: Filter, aggregate, and paginate data in Python before passing it to graphs or `AgGrid`. Only send the rows or points needed for the current view to the client.
- **Pin Dependencies**: Specify minimum or exact versions for `dash`, `plotly`, and component libraries in `requirements.txt` to avoid breaking changes on deploy.
## Callbacks
- **Dataset Size**: Do not pass massive datasets through `dcc.Store` if they can be cached server-side. Use `dcc.Store` only for lightweight state (IDs, UI toggles, query filters) with a maximum of 5MB.
- **Caching**: For large datasets, expensive database queries, heavy computations, or API requests, implement server-side caching using `flask_caching`. Decorate data-fetching operations with the `@cache.memoize()` pattern. Ensure the cache key includes relevant query parameters.
- **Input IDs**: Every `Input`, `Output`, and `State` ID referenced in a callback must be present in the layout when the callback fires. For dynamic or multi-page layouts, set `suppress_callback_exceptions = True`.
- **Prevent Callback Firing**: Apply `prevent_initial_call=True` in callback decorators that should not run on page load (e.g., actions triggered only by a button click).
- **Prevent Unnecessary Updates**: When a callback should leave an output unchanged, return `dash.no_update` instead of re-fetching or re-computing data. Use `raise PreventUpdate` to skip updating the entire callback.
- **Keep Callbacks Focused**: One callback per user interaction when possible. Split large callbacks into smaller, composable ones rather than updating many outputs from a single function.
- **Loading Spinners**: Show a spinner while data is loading to improve perceived performance by wrapping components that may be slow to update with `dcc.Loading`.
- **Background Callbacks**: Use background callbacks for long-running work. For tasks that take more than a few seconds, use `background=True` in the callback decorator, along with the configured manager: `manager=background_callback_manager`.
- **Validate Callback Outputs**: Return strings for `children`, lists of component objects for `children` on containers, dicts for `figure`, and lists of dicts for `AgGrid` `rowData` and `columnDefs`.
## Layout and Styling
- **Custom Style Sheets**: For external stylesheets and CSS files, put core layout styles, layout grids, and structural overrides into custom files inside the `assets/` directory.
- **Theme File**: Use a shared `theme.py` or `theme.js` containing color constants, spacing scales, and font definitions to pass values systematically.
- **Inline Styles**: Use inline Python dictionaries (`style={"marginRight": "10px"}`) only for highly dynamic, runtime-computed values (e.g., styling a component color based on a callback threshold). Avoid static inline styling blocks as much as possible.
- **Code Format**: Run `black` for Python formatting and Prettier for CSS formatting.
## Charts and Components
- **Graphing Library**: Use `plotly.express` for charts first—it is simpler and covers most use cases. Switch to `plotly.graph_objects` only when you need fine-grained control.
- **Component Libraries**: Prioritize component libraries in this order: Dash Design Kit (if you have access to it), then Dash Core Components combined with Dash HTML Components, then Dash Mantine Components, then Dash Bootstrap Components if required. Try to minimize the number of libraries required.
- **Data Tables**: Do not use `dash.datatable`; use `dash.AgGrid` instead.
- **AgGrid Configs**: When instantiating `dag.AgGrid`, always set the following properties:
- `dashGridOptions={"theme": "themeBalham", "animateRows": True, "pagination": True, "paginationPageSize": 10}`
- `columnSize="responsiveSizeToFit"`
- `defaultColDef={"filter": True, "sortable": True}`
## Avoid Hallucinations
- Never use `app.run_server`; only use `app.run`
- Never use obsolete patterns like `app.validation_layout`. Modern Dash handles dynamic layouts smoothly; just use `suppress_callback_exceptions=True` on app initialization if building dynamic layouts.
- Never import `dash.dependencies` items individually (from `dash.dependencies import Input`). Always use the modern syntax: `from dash import Input, Output, State, callback, clientside_callback, no_update, ALL, MATCH`.
- Never write blocking `time.sleep` loops inside a callback in production contexts; use `dcc.Interval` for asynchronous long-polling or integrate an external task queue (like Celery/Redis) if handling long-running computations.
- Never assign to callback `Input` values or mutate callback arguments in place.
- Never use `dash_table.DataTable`; use `dash.AgGrid()` instead.
- Never put secrets, API keys, or credentials in layout code or `dcc.Store`. Use environment variables and server-side logic only.
AI assistants can generate Dash apps, but the resulting app runs on localhost and can’t be shared directly. To put your app in front of colleagues or stakeholders, you need to publish it to a server.
This is where Plotly Cloud and Dash Enterprise complete the AI-assisted workflow. Hosting, scaling, and authentication are all handled by the platform—so neither you nor the AI agent need to write infrastructure code. The agent focuses entirely on your app logic and visualizations, and a single CLI command publishes the result to a production-ready environment.
The Plotly Cloud CLI (currently in early access) lets you publish directly from the command line. Install it with:
pip install "dash[cloud]"
Then publish your app:
plotly app publish --name "Q1 Sales Dashboard"
This works well with AI-assisted workflows since the agent can run the publish command after generating your app code.
If your organization uses Dash Enterprise, you or an AI agent can deploy apps using the Dash Enterprise CLI (de-client). The CLI is included in the dash-enterprise-libraries package.
Install it with:
pip install dash-enterprise-libraries --extra-index-url <your-dash-enterprise-url>/packages
Then deploy your app:
de deploy . --name "q1-sales-dashboard"
See Publishing Your App for more details on publishing options.
For the deployment context, choose the configuration that matches your publishing target and append it to your AGENTS.md file.
## Publishing
This Dash app publishes to Plotly Cloud using the Plotly Cloud CLI.
## Dependencies
Install with: `pip install "dash[cloud]"`
## Commands
```bash
# Log in (opens browser for OAuth)
plotly user login
# Publish to Plotly Cloud
plotly app publish --name "My Dashboard" --team "my-team"
# Check status — run after publishing to confirm the app is live
# Typical publish takes 1-2 minutes. Re-run until status shows "deployed"
plotly app status
# Running Locally
plotly app run app:app --debug --open
```
## Configuration
Create a `plotly-cloud.toml` in the project root:
```toml
[app]
name = "my-dashboard"
entrypoint = "app:app"
[publish]
team = "my-team-id"
```
## Publishing
This Dash app deploys to Dash Enterprise using the Dash Enterprise CLI (`de-client`).
## Dependencies
Install with: `pip install dash-enterprise-libraries --extra-index-url <your-dash-enterprise-url>/packages`
## Commands
```bash
# Log in to Dash Enterprise (opens browser)
de --host your-dash-enterprise.example.com login
# Deploy (creates the app if it doesn't exist)
de deploy . --name my-dashboard
# Check status — re-run until status shows "deployed" (typically 2-5 minutes)
# Build statuses: queued → building → built → failed
# Deploy statuses: built → deploying → deployed → failed
de apps status --name my-dashboard
de apps logs --name my-dashboard --type build
de apps logs --name my-dashboard --type runtime
de apps list # List your apps
de apps restart --name my-dashboard # Restart
de apps logs --name my-dashboard --type runtime # Runtime logs
de services create --app-name my-dashboard --type redis # Creates Redis database
de services create --app-name my-dashboard --type postgres # Creates SQL database
de services list --type all # Lists created databases
```
## Procfile (required)
Declares how to run the app:
```
web: gunicorn app:app --workers 4
```
For apps with background tasks:
```
web: gunicorn app:app --workers 4
worker: celery -A app:celery_instance worker
```
## project.toml (optional)
Build configuration and deploy scripts:
```toml
[scripts]
predeploy = "predeploy.sh"
```
## Aptfile (optional)
System-level packages:
```
unixodbc
unixodbc-dev
```
## Important Notes
- The `Procfile` is required — without it, the app won't start
- Use `gunicorn` as the WSGI server (include it in `requirements.txt`)