Deploying

Every scaffold ships deploy-ready: pick a static host for the build output, or run the live server on a platform that takes a Procfile.

Two ways to go live#

Koyo supports both of the common deployment shapes, and the scaffold includes the files for each.

  • Static hosting for sites with no dynamic routes: run koyoapp build and point a CDN or static host at .koyo/build/site. No Python is needed at serving time.
  • Live server for dynamic routes (bracket segments) and session state: run the Koyo app under uvicorn. This is the path the rest of this page covers.

What the scaffold ships#

koyoapp create writes three deployment files into every new project:

  • Procfile starts the production server with a self-contained command:
    web: python -m uvicorn koyoapp.serve:app --host 0.0.0.0 --port $PORT
  • requirements.txt pins koyoapp to the version that created the project, so the platform installs the same release you developed against.
  • .railwayignore keeps the local .venv, bytecode cache, and build output out of the upload, so containers build their own Linux environment. The same exclusions apply to any platform that rsyncs or zips the project directory.

Deploy to Railway#

Install the CLI, then from the project root:

brew install railway        # or: npm i -g @railway/cli
railway login              # opens your browser
railway init               # creates and links a project
railway up                 # builds and deploys
railway domain             # get a public URL, e.g. myapp.up.railway.app

Railpack detects Python from requirements.txt, installs the pinned dependencies, and starts the web command from the Procfile. Railway injects $PORT automatically, and the app binds 0.0.0.0 in the Procfile so the platform can reach it. Subsequent deploys are just railway up again.

Deploy to Render#

Create a Web Service pointing at the project root and set:

  • Build command: pip install -r requirements.txt
  • Start command: python -m uvicorn koyoapp.serve:app --host 0.0.0.0 --port $PORT

Render sets $PORT for you. The same start command works on Fly.io, a VPS with a reverse proxy, or any platform that runs Python processes.

Environment#

By default the server runs from the project root, so serve.py resolves app/, public/, and styles/ relative to the current directory. If the platform runs from somewhere else, point it at the project root explicitly:

KOYO_PROJECT_DIR=/path/to/project

Production mode is the default: without KOYO_DEV=1 the live reload probe and script are not registered, and errors render the generic page without a traceback.

Scaling and state#

Session state is in-memory only. It resets on restart and is not shared across processes: run a single replica unless you move state elsewhere. Static assets and the compiled styles/koyo.css ship with the app, so the server needs no build step beyond installing the pinned dependencies.