☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

How to add more applications to a running bokeh server

Community Support
hyamanieu
hyamanieu

To answer your first question, you can also simply call
bokeh serve path/to/app1 path/to/app2

``

As for your second question regarding the specific use of Server, you can see that in the docs (bokeh.server.server — Bokeh 3.3.2 Documentation) you pass a dictionary of applications. Just add them in the dictionary.

···

Le lundi 7 mai 2018 13:04:21 UTC+2, Artur Scholz a écrit :

Is it possible to add further applications (that is, bokeh documents) to a running bokeh server?

For example, consider the flask application with embedded bokeh server:
https://github.com/bokeh/bokeh/blob/0.12.15/examples/howto/server_embed/flask_embed.py

Namely, how to add further applications to the server created in this step:
server = Server({‘/bkapp’: modify_doc}, io_loop=IOLoop(), allow_websocket_origin=[“localhost:8000”])

``

Artur

⌁   Link to post
Artur_Scholz
Artur_Scholz

Thanks. I was referring to embedded server only. And my question was on how to add applications

afterwards, i.e. after having passed the applications dict to the bokeh server instantiation.

After reading through the docs and code, I am convinced that is not possible in that way.

So instead, rather than using one bokeh server and adding applications on the fly, I create one
dedicated embedded bokeh server for each application at startup, each at a distinct port.

server.py:
from threading import Thread, Lock
import socket

from bokeh.server.server import Server
from bokeh.embed import server_document
from tornado.ioloop import IOLoop

mutex = Lock()

def get_free_tcp_port():
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.bind((‘’, 0))
addr, port = tcp.getsockname()
tcp.close()
return port

class BokehServer:
“”“Bokeh server (based on Tornado HTTPServer) to synchronize client and server
documents via websocket.
“””
def init(self, application, websocket_origin=[‘*’]):
if not callable(application):
raise ValueError()
self.application = application
self.websocket_origin = websocket_origin
self.thread = Thread(target=self._server_thread)
self.thread.start()

def _server_thread(self):
    self.io_loop = IOLoop()
    with mutex:
        self.port = get_free_tcp_port()
        self.server = Server(
            self.application, io_loop=self.io_loop,
            allow_websocket_origin=self.websocket_origin,
            port=self.port)
    self.server.start()
    self.server.io_loop.start()

def get_script(self):
    return server_document('[http://localhost](http://localhost):' + str(self.port))

``

view.py
def plot(doc):

… create a bokeh figure and add as root element to doc

server = server.BokehServer(plot)

@demo.route(‘/domain/demo/view/demo-plot’)
def view_demo_plot():
script = server.get_script()
return render_template(‘demo/plot.html’, script=script)

``

···

On Tue, May 8, 2018 at 3:41 PM, hyamanieu huguesyanis.amanieu@gmail.com wrote:

To answer your first question, you can also simply call
bokeh serve path/to/app1 path/to/app2

``

As for your second question regarding the specific use of Server, you can see that in the docs (https://bokeh.pydata.org/en/latest/docs/reference/server/server.html#bokeh.server.server.Server) you pass a dictionary of applications. Just add them in the dictionary.

Le lundi 7 mai 2018 13:04:21 UTC+2, Artur Scholz a écrit :

Is it possible to add further applications (that is, bokeh documents) to a running bokeh server?

For example, consider the flask application with embedded bokeh server:
https://github.com/bokeh/bokeh/blob/0.12.15/examples/howto/server_embed/flask_embed.py

Namely, how to add further applications to the server created in this step:
server = Server({‘/bkapp’: modify_doc}, io_loop=IOLoop(), allow_websocket_origin=[“localhost:8000”])

``

Artur

–

You received this message because you are subscribed to a topic in the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this topic, visit https://groups.google.com/a/continuum.io/d/topic/bokeh/HNsguacFpYA/unsubscribe.

To unsubscribe from this group and all its topics, send an email to bokeh+unsubscribe@continuum.io.

To post to this group, send email to bokeh@continuum.io.

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/764f822a-09a3-4bdb-9b12-ec0f98a1ccfb%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.

⌁   Link to post
Bryan
Bryan

Hi,

It's probably possible to find some way to do this, since Tornado seems to support adding routes dynamically:

  Adding new handler to running python tornado server - Stack Overflow

Unfortunately it's not something I can devote time to looking into just now, but if someone plays around some and finds a way, we'd be happy to codify it more formally in the core library.

Thanks,

Bryan

···

On May 9, 2018, at 02:33, Artur Scholz <artur.scholz.79@gmail.com> wrote:

Thanks. I was referring to embedded server only. And my question was on how to add applications
afterwards, i.e. after having passed the applications dict to the bokeh server instantiation.

After reading through the docs and code, I am convinced that is not possible in that way.

So instead, rather than using one bokeh server and adding applications on the fly, I create one
dedicated embedded bokeh server for each application at startup, each at a distinct port.

server.py:
from threading import Thread, Lock
import socket

from bokeh.server.server import Server
from bokeh.embed import server_document
from tornado.ioloop import IOLoop

mutex = Lock()

def get_free_tcp_port():
    tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp.bind(('', 0))
    addr, port = tcp.getsockname()
    tcp.close()
    return port

class BokehServer:
    """Bokeh server (based on Tornado HTTPServer) to synchronize client and server
    documents via websocket.
    """
    def __init__(self, application, websocket_origin=['*']):
        if not callable(application):
            raise ValueError()
        self.application = application
        self.websocket_origin = websocket_origin
        self.thread = Thread(target=self._server_thread)
        self.thread.start()

    def _server_thread(self):
        self.io_loop = IOLoop()
        with mutex:
            self.port = get_free_tcp_port()
            self.server = Server(
                self.application, io_loop=self.io_loop,
                allow_websocket_origin=self.websocket_origin,
                port=self.port)
        self.server.start()
        self.server.io_loop.start()

    def get_script(self):
        return server_document('http://localhost:' + str(self.port))

view.py
def plot(doc):
    # ... create a bokeh figure and add as root element to doc

server = server.BokehServer(plot)

@demo.route('/domain/demo/view/demo-plot')
def view_demo_plot():
    script = server.get_script()
    return render_template('demo/plot.html', script=script)

On Tue, May 8, 2018 at 3:41 PM, hyamanieu <huguesyanis.amanieu@gmail.com> wrote:
To answer your first question, you can also simply call
bokeh serve path/to/app1 path/to/app2

As for your second question regarding the specific use of Server, you can see that in the docs (bokeh.server.server — Bokeh 3.3.2 Documentation) you pass a dictionary of applications. Just add them in the dictionary.

Le lundi 7 mai 2018 13:04:21 UTC+2, Artur Scholz a écrit :

Is it possible to add further applications (that is, bokeh documents) to a running bokeh server?

For example, consider the flask application with embedded bokeh server:
https://github.com/bokeh/bokeh/blob/0.12.15/examples/howto/server_embed/flask_embed.py

Namely, how to add further applications to the server created in this step:
server = Server({'/bkapp': modify_doc}, io_loop=IOLoop(), allow_websocket_origin=["localhost:8000"])

Artur

--
You received this message because you are subscribed to a topic in the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this topic, visit https://groups.google.com/a/continuum.io/d/topic/bokeh/HNsguacFpYA/unsubscribe\.
To unsubscribe from this group and all its topics, send an email to bokeh+unsubscribe@continuum.io.
To post to this group, send email to bokeh@continuum.io.
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/764f822a-09a3-4bdb-9b12-ec0f98a1ccfb%40continuum.io\.

For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+unsubscribe@continuum.io.
To post to this group, send email to bokeh@continuum.io.
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/CALqfExZgnqJ6172uVYg%3Dt47SYyRY_QJdSspB6qD2%2B4qk0T3jOA%40mail.gmail.com\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

⌁   Link to post
ViNMH
ViNMH

So, I have been working on a solution to this, and so far I have a (not very good) way to add applications. Trying to find a way to remove them as well.

I essentially reused a part from the __init__ code from bokeh.server.tornado.BokehTornado and called the add_handlers from tornado.web.Application.

Maybe this can be more refined and implemented inside the BokehTornado class.

from bokeh.server.contexts import ApplicationContext
from bokeh.application import Application
from bokeh.server.server import Server
from bokeh.server.urls import per_app_patterns
from tornado.web import StaticFileHandler
from typing import Dict

def add_applications(applications: Dict[str, Application], server: Server):
    
    for k, v in applications.items():
        server._tornado._applications[k] = ApplicationContext(v, url=k)

        app_patterns = []
        for p in per_app_patterns:
            route = server._tornado._prefix + ('' if k == '/' else k) + p[0]
            app_patterns.append((route, p[1], {"application_context": server._tornado._applications[k]}))
        
        websocket_path = None
        for r in app_patterns:
            if r[0].endswith('/ws'):
                websocket_path = r[0]
        if not websocket_path:
            raise RuntimeError("Couldn't find websocket path")
        for r in app_patterns:
            r[2]["bokeh_websocket_path"] = websocket_path
        
        if v.static_path is not None:
            route = server._tornado._prefix + ('' if k == '/' else k) + "/static/(.*)"
            app_patterns.append((route, StaticFileHandler, {"path": v.static_path}))
        server._tornado.add_handlers(host_pattern='.*$', host_handlers=app_patterns)
        
        server._tornado._applications[k]._loop = server._loop

        if server._started:
            server._tornado._applications[k].run_load_hook()
⌁   Link to post
c3y
c3y

Hi Artur,

I’m facing a similar situation, where I want to design some sort of dataset browser, and launching a bokeh app/ or redirecting to a running app to visualize a dataset. I’m wondering if you ever found out the best way to go about this?

⌁   Link to post
Bryan
Bryan

There’s no way to add applications to a standard Bokeh server, e.g if you are using bokeh serve. The Bokeh server can be embedded as programmatically in which case (in principle) you might be able to add applications dynamically by configuring properties and methods on the Server object directly (I have never tried, personally, though).

Can I ask why you want to add applications dynamically? If you want to e.g. add new applications based on user input, that seems like a bad idea from a security perspectice, since the user-submitted code would have unfettered access to the python interpreter.

⌁   Link to post
c3y
c3y

I see. Thanks for the advice. I am currently building a sort of browser for an image viewer built in Bokeh. So the idea is to have a list of images that can be visualized with the app, maybe in the form of an html page, and have the ability to click on an image to launch the app to visualize it. If you have thoughts on the best way to go about that, I’d greatly appreciate it.

⌁   Link to post

End of archived discussion · Replies are disabled