Skip to main content

Deploy to Posit Connect (rsconnect)

Ship a FastAPI app (with or without a bundled SPA) to Roche Posit Connect using the rsconnect-python CLI. Requires the Roche network / VPN to reach the Connect server.

One-content architecture (API + UI together)

Serve the built frontend from FastAPI so a single Connect content covers both. Two things matter for Connect’s /content/<guid>/ URL prefix:

  1. Relative asset paths in the frontend build:
    • Vite: base: "./" in vite.config.ts.
    • API base: relative ("api", not "/api") so fetch resolves under the prefix.
  2. FastAPI serves the build (static mount + SPA fallback):
from pathlib import Path
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles

STATIC = Path(__file__).resolve().parent / "static"   # built SPA copied here
if STATIC.is_dir():
    app.mount("/assets", StaticFiles(directory=STATIC / "assets"), name="assets")
    @app.get("/{full_path:path}")                       # register AFTER /api routers
    def spa(full_path: str):
        cand = STATIC / full_path
        return FileResponse(cand if full_path and cand.is_file() else STATIC / "index.html")

Build + stage the frontend (PowerShell, Windows)

cd frontend; npm run build; cd ..
Remove-Item -Recurse -Force backend\app\static -ErrorAction SilentlyContinue
Copy-Item -Recurse frontend\dist backend\app\static

Deploy

pip install rsconnect-python

# Register the server once (nickname is chosen here — reuse it in --name below)
$env:CONNECT_API_KEY = "<API_KEY>"
rsconnect add --server https://rsconnect-pred.roche.com/ --name pred-bar --api-key $env:CONNECT_API_KEY

# Deploy the backend (which embeds the UI). PowerShell continuation = backtick `
rsconnect deploy fastapi backend `
  --entrypoint app.main:app `
  --name pred-bar `
  --title "My App" `
  --exclude ".venv" --exclude "**/__pycache__" --exclude ".env"

requirements.txt must sit at the deployed dir root (backend/); Connect installs it.

Gotchas hit in practice

  • Error: The nickname "X" does not exist--name must match the nickname used in rsconnect add.
  • Unable to include ...\.venv\bin\python ... Invalid argument → the virtualenv got bundled. Exclude it: --exclude ".venv". Also exclude .env so secrets don’t ship. Or add a backend/.rscignore with .venv/, **/__pycache__/, .env, *.pyc.
  • Warning: missing Python version constraint → add backend/.python-version (e.g. 3.11).
  • Set runtime secrets (DB creds, API keys) in the Connect UI → content → Vars, never in the bundle. Verify with .../content/<guid>/api/health.

After deploy checklist

  • Frontend built with relative base and API base
  • dist copied into backend/app/static
  • .venv / .env excluded from the bundle
  • Env vars set in Connect Vars
  • /api/health responds under the content URL
Ready to get involved? Have a question, an idea, or want to work with the SPO AI Program?
Work With Us →