Supported app types
Static sites, React SPAs, Node.js services and Python web apps — with the exact settings for each.
Static site
- •For plain HTML/CSS/JS or any pre-built static output. No server runs; files are served directly over HTTPS.
- •Build command: leave empty if the files are already committed, or your generator command (e.g. npm run build).
- •Output directory: the folder containing index.html (default: public). Root directory: / (or a subfolder).
- •Example: a repo with public/index.html → type Static, output “public”, no build command.
React app (SPA)
- •For Vite / Create-React-App / any single-page app that builds to static assets. Served with SPA fallback (unknown routes return index.html).
- •Install command: npm ci. Build command: npm run build. Output directory: dist (Vite) or build (CRA).
- •Build-time variables (e.g. VITE_*/REACT_APP_*) are set under the project’s Secrets/variables before building.
- •No server runs in this mode — so a form POST or a fetch to /api/… returns 404. If your app needs a backend, see “React/Static apps that run their own server” below.
React/Static apps that run their own server
- •If your React or Static project ships its OWN Node server (an Express/SSR server.js that serves the built frontend AND your /api routes), Shipyard can run it instead of serving plain files — no separate backend, no CORS, same origin.
- •Turn it on at create time (“This app runs its own Node server”) or any time under Project → Settings → Runtime configuration → Runtime type = “Node server”. Shipyard then builds the frontend (npm run build) and runs your start command (npm start → node server.js), health-checks it, and routes traffic to it.
- •Port: Shipyard assigns the port and injects it as PORT — your server MUST listen on process.env.PORT (and bind 0.0.0.0). There are no cross-app port conflicts (each app runs in its own isolated container), so you don’t pick a port. Set a health check path (e.g. /health) that returns 200.
- •Result: your relative /api/submit (or /api/submissions) calls work in production exactly like they do locally, because the same Express process serves both.
Node.js service
- •For Express / Fastify / Nest and other long-running servers. Runs in an isolated container with zero-downtime promotion.
- •Install: npm ci. Build: npm run build (if you compile). Start command: e.g. node dist/main.js. Port: the port your server listens on.
- •Health check path: a route returning 200 when ready (e.g. /health). A new release only receives traffic after it passes the check.
Python service
- •For Flask / FastAPI / Django and other Python web servers. Runs in an isolated Python container with zero-downtime promotion (same model as Node).
- •Install runs in a venv so the app is self-contained: python -m venv .venv && .venv/bin/pip install -r requirements.txt (Shipyard puts .venv/bin on PATH at runtime). Build command is usually empty.
- •Start command: gunicorn app:app --bind 0.0.0.0:$PORT (Flask/WSGI), uvicorn main:app --host 0.0.0.0 --port $PORT (FastAPI), or python manage.py runserver 0.0.0.0:$PORT (Django). Shipyard assigns the port and injects it as PORT — bind to it.
- •Health check path: a route returning 200 when ready (e.g. /health). The auto-detector picks the framework + start command from your repo; you can override everything in Settings.
