Frontend Companion

Serve your React, Vue, or Svelte SPA alongside your backend — no separate hosting needed

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.

How requests are routed
/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

Backend routes must be under /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.
Your frontend must use npm. The build step runs npm ci && npm run build using node:lts-alpine. A package.json with a build script and a package-lock.json are required.
Slot headroom. Frontend Companion reserves 0.05 vCPU and 64 MB from your slot for the nginx sidecar. Your app needs at least 0.1 vCPU and 128 MB of headroom above its minimum to enable it.

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.

Example repo layout
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
Vite recommended. Vite outputs to 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.

Before — won't work with FC
@app.get("/users")
@app.post("/auth/login")
@app.get("/health")
After — works with FC
@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. 1

    Open your app in the portal

    Go to dash.clouderized.com → click your app → open the Frontend tab.

    2

    Enter your frontend directory

    Type the path to your frontend source folder relative to the repo root — e.g. frontend or client. This is where package.json lives.

    3

    Enable 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. 1 Your backend image is built from your Dockerfile as normal.
  2. 2 npm ci && npm run build runs inside node:lts-alpine in your frontend directory.
  3. 3 The build output (dist/) is synced to the VPS. The nginx sidecar picks it up immediately.
  4. 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.

Related docs