Skip to content

Creating a Panel App

Open My Panel Apps. The toolbar offers two ways to publish, one per runtime:

  • New Server App — build and run an app from a git repository.
  • Add WASM App — publish a static, in-browser app from a file.

A server app is built from a git repository and served at https://<your-tenant-host>/serve/<slug>/. You point PlaidCloud at a branch of a repository; it builds the code into a container, runs panel serve on it, and rebuilds automatically whenever you push to that branch.

Your repository needs two things: an entry point — a Python file that builds a Panel app and marks it .servable() — and, optionally, a requirements.txt at the repository root listing any extra packages.

my-panel-app/
├── app.py # entry point — calls .servable()
└── requirements.txt # optional; extra dependencies, at the repo root

Create app.py:

import panel as pn
pn.extension()
pn.pane.Markdown("# Hello, PlaidCloud 👋\n\nYour first server-side Panel app is running.").servable()

That’s a complete app. The .servable() call is what PlaidCloud serves — anything you want rendered must be marked servable (directly, or by being inside a servable layout).

Panel apps are interactive. This one adds a slider that updates a table live:

import pandas as pd
import panel as pn
pn.extension()
multiplier = pn.widgets.IntSlider(name="Multiplier", start=1, end=10, value=3)
@pn.depends(multiplier)
def times_table(m):
df = pd.DataFrame({"n": range(1, 6)})
df["result"] = df["n"] * m
return pn.pane.DataFrame(df, index=False)
pn.Column(
"# Times Table",
multiplier,
times_table,
).servable()

This second example imports pandas, which isn’t part of the base image, so add a requirements.txt at the repository root:

pandas

PlaidCloud installs these with pip when it builds the image.

What the platform provides — and expects. Keep these assumptions in mind when you write your app:

  • panel and bokeh are pre-installed by the platform base image. Don’t list them in requirements.txt, and avoid pinning an older Panel version — the live-update reconnect relies on a recent one.
  • The PlaidCloud client libraries (plaidcloud-rpc, plaidcloud-utilities) are pre-installed. Import plaidcloud.rpc or plaidcloud.utilities directly — don’t list them in requirements.txt.
  • requirements.txt must be at the repository root. A file in a subdirectory is ignored, even if your entry point lives in one.
  • The app runs as a non-root user on a read-only filesystem. Only /tmp is writable, so write any temporary files there (most libraries already honor $TMPDIR).
  • Don’t hardcode the port, URL prefix, or host. PlaidCloud assigns them and injects them at deploy time — just call .servable().

Server apps render in PlaidCloud’s modern Fast design by default — a clean, Fluent-style look applied platform-wide, so you get it with no code. What you control, in your app, is the theme: light, dark, or a switch the viewer can flip.

The theme is a property of the template you serve. The Fast templates — FastListTemplate (a single column) and FastGridTemplate (a responsive grid) — take two settings for it:

  • theme"default" for light or "dark". Setting it pins the app to that theme, even if a viewer adds ?theme=dark to the URL.
  • theme_toggleTrue shows a light/dark switch in the header; False hides it. It defaults to True. Hiding the switch doesn’t fix the theme on its own — pin it with theme (above); set theme_toggle=False once you have, so viewers don’t see a switch that can’t change anything.

Pick the pattern that fits your app.

Light only — best for dense reports and financial tables, which are usually hand-styled for a light background:

import panel as pn
pn.extension("tabulator")
pn.template.FastListTemplate(
title="Sales Dashboard",
theme="default", # light
theme_toggle=False, # hide the switch
main=[...],
).servable()

Dark only:

pn.template.FastListTemplate(
title="Ops Monitor",
theme="dark",
theme_toggle=False,
main=[...],
).servable()

Let the viewer choose — defaults to light, with a switch in the header. Omit theme so it follows the toggle:

pn.template.FastListTemplate(
title="Explorer",
theme_toggle=True,
main=[...],
).servable()

If you allow dark, make your tables dark-aware. A Tabulator pinned to a light table theme (theme="bootstrap"), or custom CSS with hardcoded light colors like background: #fff, renders as an unreadable white block on a dark page. Use a table theme that follows the app — pn.widgets.Tabulator(..., theme="fast") — and avoid hardcoded light colors. If a report is heavily hand-styled for light, pin it to light instead (the first pattern above).

A plain app with no template — pn.Column(...).servable() — follows Panel’s default and isn’t affected by these settings; reach for a template when you want explicit control.

Your repository must be reachable through a git connection in PlaidCloud. If you don’t have one yet, create it under Tools > Connections before publishing.

  1. Click New Server App to open the Publish Server Panel App dialog. Its settings are grouped into sections.
  2. Under Directory Settings:
    • App Name — the display name shown in the list.
    • URL Slug — both the app’s URL and its internal name, so it must be a valid DNS label: lowercase letters, digits, and hyphens, starting with a letter, 40 characters or fewer (for example, sales-dashboard). The dialog checks this before you publish.
    • Memo — an optional description.
  3. Under Git Connection and Publish Watcher:
    • Git Connection — the connection that holds your app’s repository.
    • Branch — the branch to build from. Pushes to this branch rebuild and redeploy the app automatically.
    • Entry Point — the .py file Panel should serve (your app.py).
  4. Under Runtime:
    • CPU and Memory the app’s container should request.

      Fewer resources (lower CPU / memory) let the app schedule and cold-start faster.

    • Idle (minutes) — how long the app stays warm with no traffic before it scales back to zero. The default is 5 minutes.

    • Allow Public Access — tick to allow unauthenticated access; otherwise viewers must sign in to your tenant.

  5. Under Advanced (Embedded Serving) — optional. By default the app serves only from your PlaidCloud tenant. To embed it in another site, click Add Domain and enter each domain allowed to load it, one per row — a host only, no scheme or path (for example, example.com or app.example.com:8443). Leave the list empty unless you’re embedding the app elsewhere.
  6. Click Publish.

After you publish, the app builds — its Status shows in the list and updates automatically. See Using a Panel App for what the statuses mean and how to open the app once it is ready.

The app’s URL works only once its build status is Ready, and the first request after it has been idle spins it up (~15 seconds).

A WASM app runs in the browser from a pre-built HTML file.

  1. Click Add WASM App to open the Publish Serverless Panel App dialog.
  2. Enter an App Name and Version.
  3. Choose the App HTML Location — the HTML file in a document account.
  4. Enter an App URL Slug and an optional Memo.
  5. Click Publish. A WASM app has no build step and is served immediately.