# Structuring a multi-page app

**URL:** <https://community.plotly.com/t/structuring-a-multi-page-app/13328>\
**Category:** Dash Python\
**Created:** [September 5, 2018, 7:42pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328 "2018-09-05T19:42:44Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![austin](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/austin/32/3328_2.png) [@austin](https://community.plotly.com/u/austin)\
**Post date:** [September 5, 2018, 7:42pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/1 "2018-09-05T19:42:44Z")

</div>

So I’d like to build a multi-page app where each page’s code is saved in its own file. I’ve attempted to follow the demo provided in the documentation, but it failed for me: [URL Routing and Multiple Apps | Dash for Python Documentation | Plotly](https://dash.plot.ly/urls)

Is this demo 100%? It seems like maybe the `app.py` example is missing something. I’m attempting to troubleshoot on my own, but wanted to know if others have successfully replicated this demo. Thanks!

---

<div class="post-metadata">

**Author:** ![austin](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/austin/32/3328_2.png) [@austin](https://community.plotly.com/u/austin)\
**Post date:** [September 5, 2018, 8:32pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/2 "2018-09-05T20:32:01Z")

</div>

I modified the demo provided in the Dash documentation listed above, and successfully got it to work. It was necessary to include all of the callbacks in the primary file (app.py) – not sure if this is a best practice, but I couldn’t get it to work otherwise.

### File structure is as follows:

main.py  
pages folder:  
— empty file named “\_ \_ init \_ \_.py”  
— page\_1.py  
— page\_2.py  
— index.py

### main.py

```auto
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from pages import index
from pages import page_1
from pages import page_2

print(dcc. __version__ ) # 0.6.0 or above is required

app = dash.Dash()

app.config.suppress_callback_exceptions = True

app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])

# Page 1 callback
@app.callback(dash.dependencies.Output('page-1-content', 'children'),
              [dash.dependencies.Input('page-1-dropdown', 'value')])
def page_1_dropdown(value):
    return 'You have selected "{}"'.format(value)

# Page 2
@app.callback(Output('page-2-content', 'children'),
              [Input('page-2-radios', 'value')])
def page_2_radios(value):
    return 'You have selected "{}"'.format(value)

# Index Page callback
@app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/page-1':
        return page_1.page_1_layout
    elif pathname == '/page-2':
        return page_2.page_2_layout
    else:
        return '404'

app.css.append_css({
    'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'
})

if __name__ == ' __main__':
    app.run_server(debug=True)

```

### page\_1.py

```auto
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

page_1_layout = html.Div([
    html.H1('Page 1'),
    dcc.Dropdown(
        id='page-1-dropdown',
        options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']],
        value='LA'
    ),
    html.Div(id='page-1-content'),
    html.Br(),
    dcc.Link('Go to Page 2', href='/page-2'),
    html.Br(),
    dcc.Link('Go back to home', href='/'),

])

```

### page\_2.py

```auto
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

page_2_layout = html.Div([
    html.H1('Page 2'),
    dcc.RadioItems(
        id='page-2-radios',
        options=[{'label': i, 'value': i} for i in ['Orange', 'Blue', 'Red']],
        value='Orange'
    ),
    html.Div(id='page-2-content'),
    html.Br(),
    dcc.Link('Go to Page 1', href='/page-1'),
    html.Br(),
    dcc.Link('Go back to home', href='/')
])

```

### index.py

```auto
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

index_page = html.Div([
    dcc.Link('Go to Page 1', href='/page-1'),
    html.Br(),
    dcc.Link('Go to Page 2', href='/page-2'),
])

```

---

<div class="post-metadata">

**Author:** ![roman](https://avatars.discourse-cdn.com/v4/letter/r/ed8c4c/32.png) [@roman](https://community.plotly.com/u/roman)\
**Post date:** [September 7, 2018, 6:13pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/3 "2018-09-07T18:13:53Z")

</div>

[https://yadi.sk/d/WZURkNcP3VawdW](https://yadi.sk/d/WZURkNcP3VawdW)

here is multipage app organized 1page=1file callbacks are placed inside this files + custom css. it can be usefull as template to start with

---

<div class="post-metadata">

**Author:** ![Vlad](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/vlad/32/1369_2.png) [@Vlad](https://community.plotly.com/u/Vlad)\
**Post date:** [September 11, 2018, 9:08pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/4 "2018-09-11T21:08:14Z")

</div>

Thank you for this! How do you serve it? gunicorn? Does it work with multiple workers?

---

<div class="post-metadata">

**Author:** ![roman](https://avatars.discourse-cdn.com/v4/letter/r/ed8c4c/32.png) [@roman](https://community.plotly.com/u/roman)\
**Post date:** [September 11, 2018, 9:25pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/5 "2018-09-11T21:25:48Z")

</div>

I use it with nginx as proxy + gunicorn, but nginx is not necessary. Yes it works with multiple workers.

---

<div class="post-metadata">

**Author:** ![Razvan006](https://avatars.discourse-cdn.com/v4/letter/r/848f3c/32.png) [@Razvan006](https://community.plotly.com/u/Razvan006)\
**Post date:** [December 5, 2018, 4:53pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/6 "2018-12-05T16:53:54Z")

</div>

Hi Roman,  
THx for sharing.  
Is the link still active?  
It does not work for me.

---

<div class="post-metadata">

**Author:** ![roman](https://avatars.discourse-cdn.com/v4/letter/r/ed8c4c/32.png) [@roman](https://community.plotly.com/u/roman)\
**Post date:** [December 5, 2018, 5:05pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/7 "2018-12-05T17:05:39Z")

</div>

updated link [https://yadi.sk/d/JnM7BvKbJp3EdA](https://yadi.sk/d/JnM7BvKbJp3EdA)

---

<div class="post-metadata">

**Author:** ![Razvan006](https://avatars.discourse-cdn.com/v4/letter/r/848f3c/32.png) [@Razvan006](https://community.plotly.com/u/Razvan006)\
**Post date:** [December 5, 2018, 5:18pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/8 "2018-12-05T17:18:32Z")

</div>

Thank you very much @roman !

---

<div class="post-metadata">

**Author:** ![fkromer](https://avatars.discourse-cdn.com/v4/letter/f/a88e4f/32.png) [@fkromer](https://community.plotly.com/u/fkromer)\
**Post date:** [September 18, 2019, 4:21pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/9 "2019-09-18T16:21:49Z")

</div>

> [@roman](#):
>
> updated link [https://yadi.sk/d/JnM7BvKbJp3EdA](https://yadi.sk/d/JnM7BvKbJp3EdA)

Is the link still working? Does not work for me.

---

<div class="post-metadata">

**Author:** ![Soerendip](https://avatars.discourse-cdn.com/v4/letter/s/d2c977/32.png) [@Soerendip](https://community.plotly.com/u/Soerendip)\
**Post date:** [December 20, 2019, 12:32pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/11 "2019-12-20T12:32:58Z")

</div>

When I try to run this code I get a black page with 404 and no error.

---

<div class="post-metadata">

**Author:** ![nilsleh](https://avatars.discourse-cdn.com/v4/letter/n/eb8c5e/32.png) [@nilsleh](https://community.plotly.com/u/nilsleh)\
**Post date:** [January 23, 2020, 10:35am UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/12 "2020-01-23T10:35:42Z")

</div>

I have tried both approaches from the tutorial and also just see 404. So somehow the pathnames do not get passed correctly?

---

<div class="post-metadata">

**Author:** ![vtyagi490](https://avatars.discourse-cdn.com/v4/letter/v/d78d45/32.png) [@vtyagi490](https://community.plotly.com/u/vtyagi490)\
**Post date:** [September 11, 2020, 9:23am UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/13 "2020-09-11T09:23:28Z")

</div>

Hii, Actually It is returning 404 from Main.py file. You need to change it with index.index\_page ,  
And problem will get solved

---

<div class="post-metadata">

**Author:** ![mail8](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/mail8/32/31560_2.png) [@mail8](https://community.plotly.com/u/mail8)\
**Post date:** [January 14, 2021, 6:30pm UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/14 "2021-01-14T18:30:50Z")

</div>

It looks like this app only separates layouts into different files. But only the main file is creating an app instance. Does that mean all the callbacks have to be included in the main file?

---

<div class="post-metadata">

**Author:** ![HarishOsthe](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/harishosthe/32/9949_2.png) [@HarishOsthe](https://community.plotly.com/u/HarishOsthe)\
**Post date:** [August 9, 2021, 4:47am UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/15 "2021-08-09T04:47:42Z")

</div>

Yes @mail8, you’re right !

For more info [checkout this doc](https://dash.plotly.com/urls#structuring-a-multi-page-app)

---

<div class="post-metadata">

**Author:** ![mail8](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/mail8/32/31560_2.png) [@mail8](https://community.plotly.com/u/mail8)\
**Post date:** [September 3, 2021, 1:34am UTC](https://community.plotly.com/t/structuring-a-multi-page-app/13328/16 "2021-09-03T01:34:19Z")

</div>

I created a multi-page app where the different callbacks are collected in functions. So, only the callbacks relevant for a certain view are in the same file with the layout information. In principle these could be split into layout and callback files as well:

> **[ms-mint/ms\_mint/app at develop · soerendip/ms-mint](https://github.com/soerendip/ms-mint/tree/develop/ms_mint/app)**
>
> develop/ms\_mint/app

If you are interested.
