Skip to main content
import upnext

api = upnext.Api("my-app")

api.static(
    "/",
    directory="./frontend",
    package_manager=upnext.PackageManager.BUN,
    output="./frontend/dist",
)
api.static() lets you serve frontend assets (React, Vite, TanStack, etc.) directly from your UpNext API. UpNext automatically builds your frontend and serves the output — no need to commit built assets to git.

Basic usage

Mount a directory of static files at a URL path:
api.static("/assets", directory="./public")
This serves files from ./public at /assets — for example, ./public/logo.png is served at /assets/logo.png.

Frontend builds

When you set a package_manager, UpNext provides sensible defaults for build_command and dev_command:
api.static(
    "/",
    directory="./frontend",
    package_manager=upnext.PackageManager.BUN,
    output="./frontend/dist",
)
# Defaults: build_command="bun run build", dev_command="bun dev"
You can override the defaults if your project uses different commands:
api.static(
    "/",
    directory="./frontend",
    package_manager=upnext.PackageManager.BUN,
    build_command="bun run build:prod",
    dev_command="bun run dev --port 3000",
    output="./frontend/dist",
)

Supported package managers

Package ManagerValueDefault buildDefault devInstall command
BunPackageManager.BUNbun run buildbun devbun install --frozen-lockfile
npmPackageManager.NPMnpm run buildnpm run devnpm ci
YarnPackageManager.YARNyarn buildyarn devyarn install --frozen-lockfile
pnpmPackageManager.PNPMpnpm buildpnpm devcorepack enable && pnpm install --frozen-lockfile

Running modes

Production (default)

upnext run service.py
Installs frontend dependencies, runs build_command, then serves the built output via FastAPI.

Dev mode

upnext run service.py --dev
Starts frontend dev servers (e.g. bun dev) as subprocesses alongside the Python API, giving you HMR and hot reload. Also enables FastAPI debug mode.

Skip build (Docker / cloud)

upnext run service.py --skip-build
Skips the install and build steps — use this when assets are already built (e.g. inside a Docker container or cloud deployment).

SPA mode

By default, static mounts use SPA (Single Page Application) mode. This means any request that doesn’t match a static file returns index.html, enabling client-side routing.
# SPA mode (default) — unmatched routes serve index.html
api.static("/", directory="./frontend/dist", spa=True)

# Non-SPA mode — unmatched routes return 404
api.static("/docs", directory="./docs/build", spa=False)

Multiple mounts

You can mount multiple static directories on the same API:
api = upnext.Api("my-app")

# Main SPA frontend
api.static(
    "/",
    directory="./frontend",
    package_manager=upnext.PackageManager.BUN,
    output="./frontend/dist",
)

# Documentation site
api.static(
    "/docs",
    directory="./docs",
    package_manager=upnext.PackageManager.NPM,
    output="./docs/build",
    spa=False,
)
API routes always take priority over static files, so your endpoints won’t be shadowed. Static mounts are applied after all routes are registered, and path="/" is always mounted last — you can call api.static() anywhere in your code without worrying about ordering.

Static options

ParameterTypeDefaultDescription
pathstrrequiredURL path to mount at
directorystrrequiredDirectory containing static files (or source)
package_managerPackageManagerNonePackage manager for build/dev
build_commandstrauto from package_managerCommand to build frontend assets
dev_commandstrauto from package_managerCommand to start dev server
outputstrNoneDirectory containing built output
spaboolTrueEnable SPA fallback to index.html
When package_manager is set, build_command and dev_command are automatically derived. Override them only if your project uses non-standard commands.

Next: Context

Track progress, save checkpoints, and send structured logs.