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:
- Relative asset paths in the frontend build:
- Vite:
base: "./"invite.config.ts. - API base: relative (
"api", not"/api") sofetchresolves under the prefix.
- Vite:
- 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→--namemust match the nickname used inrsconnect add.Unable to include ...\.venv\bin\python ... Invalid argument→ the virtualenv got bundled. Exclude it:--exclude ".venv". Also exclude.envso secrets don’t ship. Or add abackend/.rscignorewith.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
baseand API base -
distcopied intobackend/app/static -
.venv/.envexcluded from the bundle - Env vars set in Connect Vars
-
/api/healthresponds under the content URL