What is Frontend Companion?
Frontend Companion adds an nginx sidecar to your app slot that builds and serves your frontend (React, Vue, Svelte, or any framework that outputs static files) alongside your backend — all from a single Clouderized slot.
When enabled, Clouderized automatically runs npm run build on every push and serves the output. Your backend keeps running as-is — the nginx sidecar sits in front and routes traffic based on the URL path.
/api/*
Proxied to your backend container
/*
Served as static files from the built frontend
/unknown-path
Falls back to index.html — client-side routing works out of the box
Requirements
/api — the nginx sidecar only proxies paths starting with /api to your backend. Routes like /health, /auth/login, or /users will not reach your backend — they'll be served as static files instead.
npm ci && npm run build using node:lts-alpine. A package.json with a build script and a package-lock.json are required.
Repo structure
Your frontend source lives alongside your backend in the same repo
Keep your frontend source in a subdirectory of the repo (e.g. frontend/ or client/). The directory you enter in the portal is where Clouderized looks for package.json and runs the build.
my-app/
├── Dockerfile ← your backend Dockerfile
├── main.py ← backend source
├── requirements.txt
└── frontend/ ← frontend source (this is your "Frontend directory")
├── package.json
├── package-lock.json
├── vite.config.js
└── src/
└── App.jsx
dist/ by default, which is what Clouderized expects. Create React App outputs to build/ — if you use CRA, add "build": "react-scripts build && mv build dist" to your package.json scripts, or migrate to Vite.
Prefixing your backend routes with /api
All backend routes must be under /api. If your backend currently uses top-level routes, prefix them before enabling Frontend Companion.
@app.get("/users")
@app.post("/auth/login")
@app.get("/health")
@app.get("/api/users")
@app.post("/api/auth/login")
@app.get("/api/health")
Update your frontend's API base URL to match: const API = "/api"
Enabling Frontend Companion
Done entirely from the portal — no config files to edit
-
1
Open your app in the portal
Go to dash.clouderized.com → click your app → open the Frontend tab.
2Enter your frontend directory
Type the path to your frontend source folder relative to the repo root — e.g.
frontendorclient. This is wherepackage.jsonlives.3Enable and redeploy
Toggle Frontend Companion on and click Save + Redeploy. The next deploy will build your frontend and start the nginx sidecar.
What happens on every push
When Frontend Companion is enabled, the deploy pipeline adds a build step before starting your containers:
-
1
Your backend image is built from your
Dockerfileas normal. -
2
npm ci && npm run buildruns insidenode:lts-alpinein your frontend directory. -
3
The build output (
dist/) is synced to the VPS. The nginx sidecar picks it up immediately. - 4 Both your backend container and the nginx sidecar start. Traffic routes through nginx.
Resource allocation
When Frontend Companion is enabled, the nginx sidecar reserves a small portion of your slot's resources. The rest goes to your backend.
| Component | CPU | RAM |
|---|---|---|
| nginx sidecar (FC) | 0.05 vCPU | 64 MB |
| Your backend | slot total − 0.05 | slot total − 64 MB |
The portal shows your backend's effective allocation after the FC reserve is subtracted. Your slot total is unchanged.
Restarting the nginx sidecar
The Restart FC button in the portal restarts only the nginx sidecar — your backend keeps running without interruption. Use this if you've pushed a frontend-only change and want to reload the served files without a full redeploy.
Troubleshooting
Build step fails: "Frontend directory not found"
The directory you entered in the portal doesn't exist in your repo. Check the path — it must be relative to the repo root and contain a package.json. Example: if your frontend is in client/, enter client (no leading slash).
Build step fails: "npm run build" error
Check your package.json has a build script and a committed package-lock.json. Run the build locally first to catch errors before pushing.
API calls return 404 or serve the wrong content
Your backend routes must start with /api. If a route like /health is returning HTML instead of JSON, it's being handled by nginx (not your backend). Prefix all backend routes with /api.
Client-side routes return 404 on hard refresh
This shouldn't happen — nginx is configured with try_files $uri $uri/ /index.html which handles SPA routing. If you're seeing this, make sure you're accessing the app through the Clouderized URL (not running nginx locally with a different config).
"Not enough resources to enable Frontend Companion"
Your slot doesn't have enough headroom. Go to the Subscription view in the portal and increase your app's resource allocation, or disable another app to free up capacity. You need at least 0.1 vCPU and 128 MB above the app minimum.
Using Create React App (build output is build/ not dist/)
Clouderized expects the build output in dist/. The easiest fix: update your build script in package.json to react-scripts build && mv build dist. Alternatively, migrating to Vite is straightforward and outputs to dist/ by default.