What you are actually hosting
A React app runs in the visitor's browser. When you run npm run build, Vite (or Create React App) compiles your components into plain HTML, JavaScript and CSS files: dist/ for Vite, build/ for Create React App. Those files are all a server needs to deliver — there is no React running on the server, no database connection and nothing to keep "awake".
That has two consequences. First, hosting a React front end is cheap and fast, and a CDN can cache it all. Second, anything secret cannot live in it: every API key you put into a React build is visible to anyone who opens the browser's developer tools. Secrets belong in a back-end API (Node.js, Python, PHP or Java), which the React app calls.
Step 1: make a production build locally first
Before deploying anywhere, prove the build works on your own computer:
- npm ci (or npm install) — install exactly the dependencies in package-lock.json.
- npm run build — create the production files; fix any errors it reports.
- npm run preview (Vite) or npx serve -s build (Create React App) — open the printed address and click through the app.
- Commit package-lock.json, and never commit node_modules or the dist/build folder to Git.
Step 2: environment variables behave differently in React
This trips up almost everyone. In a React app, environment variables are read at build time and copied into the JavaScript files. Changing them on the server afterwards does nothing until you build again.
Only variables with the right prefix are exposed: VITE_ for Vite (read as import.meta.env.VITE_API_URL) and REACT_APP_ for Create React App (process.env.REACT_APP_API_URL). A variable without the prefix is silently undefined in the browser — the most common reason an app works locally and breaks in production. And again: these values are public. Put API base URLs and public keys here, never secret keys.
Step 3: the refresh 404 and how to fix it
Your app works when you click through it, but refreshing /dashboard or opening a shared link to /products/42 shows 404 Not Found. This happens because React Router handles those paths inside the browser; the server has no file called /dashboard, so it answers 404 before React ever loads.
The fix is an SPA fallback: the server must return index.html for every path that is not a real file, and let React Router take over. How you set it depends on the server:
- A Node.js static server: serve -s dist (the -s flag means single-page app) or an Express catch-all route that sends index.html.
- nginx: try_files $uri $uri/ /index.html; in the site's location block.
- Apache: a rewrite rule in .htaccess that sends unknown paths to index.html.
- No server control at all: switch to HashRouter (URLs like /#/dashboard) — it works anywhere but looks less clean and is worse for SEO.
Hosting a React app on Cloud Ninza, step by step
React apps run on the Node.js plans, which build the app on the server and serve it with the fallback already set:
- Create an app → Node.js → choose a plan and enter your domain (or take a free cloudninza.in address to start).
- In App settings, pick the preset "Static build (React, Vue, Angular, Vite)". It fills in install (npm ci), build (npm run build) and a start command that serves dist with SPA fallback on the app's own port. For Create React App, change dist to build in the start command.
- Add your VITE_ or REACT_APP_ variables under environment variables before the first build.
- Bring the code: connect GitHub on the Git page (every push to your branch builds and deploys automatically, with health check and automatic rollback), or upload a zip in the File Manager and press Deploy.
- Point the domain with the A records from the Domains page; free HTTPS is issued automatically.
Plans for apps start at ₹199 a month billed yearly, and every plan includes free SSL and backups twice a day.
React with a back-end API
Most real apps have an API too: Express or NestJS, Django or FastAPI, Laravel, Spring Boot. Two common layouts work well. Put the API on its own subdomain (api.yourdomain.in) as a second app and call it from React with VITE_API_URL=https://api.yourdomain.in — remember to allow that origin in the API's CORS settings. Or serve the React build from the API itself (Express static files plus a catch-all), so both share one domain and you avoid CORS entirely. Either way, keep secrets and database credentials only on the API side.
Production checklist for React apps
A few details separate a demo from a site that feels fast and reliable:
- Set the right base path: if the app lives in a subfolder, set base in vite.config.js (or homepage in package.json for CRA).
- Cache wisely: built files have hashed names and can be cached for a year; index.html should not be cached, so new deploys show at once.
- Check bundle size with the build output; lazy-load heavy routes with React.lazy.
- Add a real 404 route inside React Router for paths that do not exist.
- Add a page title and meta description per route if search traffic matters — or consider Next.js for server rendering.
Common errors after deploying React
A blank white page usually means the JavaScript files 404 because the base path is wrong — open the browser console and look at the failing URLs. "undefined" API URLs mean a variable is missing its VITE_/REACT_APP_ prefix or was added after the build. CORS errors mean the API does not allow your domain. An old version showing after a deploy is caching of index.html — hard-refresh once and check the cache headers. And 404 on refresh is the missing SPA fallback described above.
React, Next.js or plain static hosting?
A plain React (Vite) app is perfect for dashboards, admin panels, tools and apps behind a login, where search engines do not need to read each page. For marketing sites, blogs and shops that live on Google traffic, Next.js renders pages on the server and is usually the better choice — we have a separate Next.js hosting guide. If your site is just a few pages without interactivity, a static HTML site on a PHP plan is the simplest of all.
Key takeaways
The short version, for anyone skimming:
- A React build is static files: dist/ for Vite, build/ for Create React App.
- Environment variables are baked in at build time, need the VITE_ or REACT_APP_ prefix, and are public.
- Fix 404 on refresh with an SPA fallback that returns index.html for unknown paths.
- Keep secrets in a back-end API, never in the React build.
- On Cloud Ninza, the "Static build" preset, Git deploys and automatic HTTPS do the hosting work for you.
Node.js Hosting from ₹2,388/year
Run Express APIs and Next.js apps on the Node.js version you choose, with environment variables, logs and a set RAM allowance. Node.js 18, 20, 22, 24 or 26 · From 256 MB app RAM · Your code from Git or a ZIP.
Hosting from ₹99 a month on servers in India
WordPress, PHP, Node.js, Python and Java plans with free SSL and your choice of version. Create your account, pick a plan and pay by UPI, card or netbanking; your hosting is created automatically and you get your login by email, usually within minutes.