Skip to main content

Stack Reference

Plug these values into the environment pattern. Pick one backend row, one front-end row, and a serving model — then enter the corresponding values in each environment tab. The Examples show full combinations end to end.

Backends

The backend determines the runtime to install (via the pre-clone script, if it isn't already in the base image), the Post-clone Action that restores packages, and the Start Command.

BackendRuntime in base image?Install dependenciesStart commandDefault port
Node.js (Express)Yes (Node.js 24)npm cinode index.js3000
.NET (ASP.NET Core)No — install the SDKdotnet restoredotnet run --urls http://0.0.0.0:50005000
Java (Spring Boot)No — install a JDKmvn -q package -DskipTestsjava -jar target/app.jar8080
Python (FastAPI)Yes (Python 3)pip install --break-system-packages -r requirements.txtuvicorn main:app --host 0.0.0.0 --port 80008000
PHP (built-in server)No — install PHP (Composer if used)composer install (if used)php -S 0.0.0.0:8000 router.php8000
Ports in the reference apps

The Default port column shows each stack's conventional port. The reference apps standardize every backend's API on port 3001 so the front-end proxy config is identical across the grid — so the two-process examples use 3001, not the default above. Use whatever port your app actually binds.

note

PHP apps are often server-rendered (for example Laravel with Blade templates) with no separate SPA. In that case skip the front-end matrix — PHP serves the HTML itself, which is a single-origin setup with no front-end build step. See the PHP example.

Installing Python packages on the base image

The base image's Python is PEP 668 "externally managed", so a plain pip install fails the build with error: externally-managed-environment. In the container, pass --break-system-packages (as shown above) — it's safe because the build container is disposable. When running on your own machine instead, use a virtualenv (python3 -m venv .venv && .venv/bin/pip install -r requirements.txt) rather than that flag.

Hot-reloading the backend

For an edit-and-refresh dev loop, run the backend in watch mode so it reloads on code changes instead of needing a manual restart: dotnet watch run, node --watch index.js, uvicorn … --reload, or Spring Boot DevTools (then mvn -q -o compile triggers the restart; java -jar is for production). The reference apps run their backends this way, so the API hot-reloads just like the front-end dev server. A new API value still appears on the next browser refresh, since the page fetches /api/hello on load.

Installing a runtime (the pre-clone script)

You don't maintain a Dockerfile — CoderFlow generates it from your environment settings (preview it on the Build tab). Node.js and Python are already in the base image, so they need nothing here. For .NET, Java, and PHP, paste the runtime install into the pre-clone script on the Build tab (under Scripts → pre-clone) — raw Dockerfile instructions, injected before any repo is cloned:

.NET SDK

RUN curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh \
&& bash /tmp/dotnet-install.sh --channel 10.0 --install-dir /usr/local/dotnet \
&& ln -sf /usr/local/dotnet/dotnet /usr/local/bin/dotnet \
&& rm /tmp/dotnet-install.sh
ENV DOTNET_ROOT=/usr/local/dotnet

JDK 21 (Temurin) + Maven

RUN apt-get update \
&& apt-get install -y wget gnupg ca-certificates apt-transport-https \
&& mkdir -p /etc/apt/keyrings \
&& wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor -o /etc/apt/keyrings/adoptium.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb $(. /etc/os-release && echo $VERSION_CODENAME) main" > /etc/apt/sources.list.d/adoptium.list \
&& apt-get update && apt-get install -y temurin-21-jdk maven \
&& rm -rf /var/lib/apt/lists/*
ENV JAVA_HOME=/usr/lib/jvm/temurin-21-jdk-amd64

This pins JDK 21 (LTS) regardless of the base image's default. For a different version, change temurin-21-jdk and JAVA_HOME together — or use the distro's default-jdk to take whatever it provides.

PHP + Composer

RUN apt-get update \
&& apt-get install -y php-cli php-mbstring php-xml php-curl php-zip composer unzip \
&& rm -rf /var/lib/apt/lists/*

Add the extensions your framework needs (for example php-pdo, php-mysql, php-sqlite3). For a specific PHP version, add the Sury APT repository before installing.

Proxying to a running server

Some environments don't start a server in the container at all — they proxy to an application server that's already running: set a Proxy URL on the Application Server instead of a Start Command. Use it when the app runs outside the container — a staging or remote dev server, or a hard-to-containerize app. A common case is an IBM i green-screen (5250) or Rich Display application served by Profound UI Genie, where an Interactive Sessions connection auto-configures the proxy for you — see Setting up an IBM i environment.

Front ends

The front end is nearly interchangeable from CoderFlow's point of view: in single-origin you build it to static files, and in two-process you run its dev server with a proxy. Only the commands differ — and with no framework there's nothing to build, since the files are served as-is.

Front endCreateBuild → output (single-origin)Dev server (two-process)Proxy configDev port
Angularnpx -p @angular/cli@22 ng new clientng builddist/browserng serve --proxy-config proxy.conf.jsproxy.conf.js (JavaScript)4200
React (Vite)npm create vite@latest client -- --template react-tsnpm run builddistnpm run devserver.proxy in vite.config.ts5173
Vue (Vite)npm create vue@latest clientnpm run builddistnpm run devserver.proxy in vite.config.ts5173
None (vanilla HTML/CSS/JS)write .html / .css / .js by handnone — the files are the outputnone (or a static live-reload server)n/an/a

Notes:

  • Single-origin — after building, copy the output into the directory the backend serves (for example, ASP.NET Core's wwwroot, or a static folder served by Express). Build with a relative base path (Angular: --base-href ./; Vite: base: './') so assets load correctly under CoderFlow's task-proxy path.
  • Two-process — the proxy forwards /api to the backend, and the Launch URL points at the dev-server port. Point the proxy target at the backend's port (and allow overriding it with an environment variable so the same config works locally and in a container).
  • None (vanilla HTML/CSS/JS) — there's no build step, so single-origin has no rebuild friction: the backend serves the files as written, and an edit shows on the next refresh. Two-process doesn't apply unless you add a static live-reload server (for example live-server or browser-sync). For a site with no backend at all, serve the folder directly with npx serve or python -m http.server — the simplest possible environment, with no runtime to install.

Mixing and matching

To assemble any combination, take one backend row and one front-end row and drop their values into the environment pattern:

  • pre-clone (Build → Scripts) — the backend's runtime install (skip for Node.js/Python).
  • Post-clone Action (Repositories tab, per repo) — install that repo's dependencies (dotnet restore, npm ci, …; use Custom command to cover both backend and front end).
  • post-clone (Build → Scripts) — optional: a build step that spans repos or isn't tied to one.
  • setup.sh (Build → Scripts) — single-origin only: build the front end into the folder the backend serves (runs at container start, against the task's code).
  • Application Server — the start command(s) and ports for your serving model.

For example, Java + React + two-process: the pre-clone script installs a JDK and Maven; the Post-clone Action runs mvn -q package -DskipTests && npm ci (a Custom command); the Start Command runs java -jar target/app.jar & then npm run dev; Ports are 8080 and 5173; the Launch URL is / on 5173.