How to host a React app

To host a React app, run the build and publish the generated folder (dist, with Vite) on a server that serves static files. Configure the server to return index.html for the app's routes.

Updated 5 min read

Learning objectives

After reading this article you will be able to:

  • Generate a production build of a React app with Vite
  • Make React Router routes survive a page reload
  • Set environment variables and point a custom domain at the app
On this page

A React app built with Vite does not run on a server. It becomes a folder of files (an index.html, JavaScript, CSS and images) and the browser runs React. Hosting it means publishing that folder somewhere that serves it over HTTPS. You can do it in a few minutes, but two details trip up many people: routes that return 404 on reload, and environment variables that "disappear" or leak.

The examples use Vite, one of the build tools the React documentation points to for people assembling their own project. Create React App was deprecated for new apps in February 2025.

React sourcesrc/npm run buildwrites distdist/index.html+ assetsuploadBrowserGET /aboutStaticserver/assets/*file existsindex.htmlnot a file404no fallback
The build becomes files; the server returns index.html for every route that is not a file, and React Router picks the screen.

What do you need before you start?#

  • A recent Node.js version that meets the minimum listed in the Vite documentation.
  • A React project with Vite. To create one from scratch:
bash
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev

The -- before --template is required on npm 7 or later. Use --template react-ts for TypeScript. npm run dev starts the development server, which is for coding only and does not go to production.

How do you generate the production build?#

bash
npm run build
npm run preview

build runs vite build and writes everything to dist/, minified. preview serves dist/ at http://localhost:4173 so you can check the result. The Vite docs warn that preview is not a production server.

The dist/ folder is what you publish. Your source code, node_modules and .env files stay out. If the site will live under a subpath (example.com/app/), set base: '/app/' in vite.config.js. On a custom domain or subdomain, the default '/' is correct.

Why do routes return 404 when you reload the page?#

With React Router in browser mode, the URL /about only exists inside JavaScript:

jsx
import { createBrowserRouter, RouterProvider } from "react-router";

const router = createBrowserRouter([
  { path: "/", element: <Home /> },
  { path: "/about", element: <About /> },
]);

export default function App() {
  return <RouterProvider router={router} />;
}

Clicking a link works because the browser doesn't request anything from the server. When you reload /about, though, the browser requests that path from the server, which looks for a file named about, finds none and answers 404. The server must return index.html for every path that is not a file, and let React Router pick the screen.

Each server does this differently. On Firebase Hosting, for example, it is a rewrites rule in firebase.json pointing ** to /index.html. On Nginx, it is try_files $uri /index.html;. If your server has no such rule, deep routes break. The same applies to an SPA generated by React Router's framework mode with ssr: false in react-router.config.ts.

For pages that need SEO and content on first load, a pure SPA is limited: see SSR vs SSG vs static and how to host a Next.js app.

How do you use environment variables in React?#

Vite only exposes variables prefixed with VITE_ to your code, read through import.meta.env. In a .env.production file:

bash
VITE_API_URL=https://api.example.com
js
const res = await fetch(`${import.meta.env.VITE_API_URL}/products`);

The value is written into the JavaScript at build time. Changing the variable later requires a new build, and any visitor can read the value in the page's code. That is why the Vite docs say VITE_* variables should not contain sensitive information such as API keys. Secrets belong in a backend (see how to host an API), and the front end calls that backend. For the general concept, read what environment variables are.

How do you publish the dist folder?#

The exact steps depend on where you host, but the principle is the same: send the contents of dist/ (not the folder itself) to a static server, with index.html at the root. Check before publishing:

  1. npm run build finished without errors.
  2. npm run preview opens the app and navigation between routes works.
  3. The fallback to index.html is configured on the server.
  4. No .env or secret ended up in dist/, because everything there is public.

After deploying, open a deep route directly in the address bar (for example, /about) and reload. If it loads, the fallback is right. For the full cycle, see what is deployment and how to host a website.

How do you add a custom domain?#

Once the app responds at the provider's address, point your domain at it using the DNS records the provider tells you to create (usually a CNAME for subdomains such as www). HTTPS is normally issued automatically once DNS propagates. The steps are in how to point a domain to your app and how to use a custom domain.

What are the common mistakes?#

  • Blank screen in production: Vite's base is wrong for where the site lives, so files under /assets return 404. Check the browser console and the Network tab.
  • 404 on reload: the fallback to index.html is missing, as explained above.
  • import.meta.env.VITE_X is undefined: the variable lacks the VITE_ prefix, or it was set after the build.
  • Old site after publishing: the browser or CDN cached index.html. Files in assets/ carry a hash in their name, so only index.html should have short caching. See what is Cache-Control.

How to do this on Square Cloud#

A React app built with Vite runs on Square Cloud's static sites runtime. You run npm run build and upload the contents of dist/ as a ZIP in the dashboard; the CLI, GitHub and the VS Code extension are the other ways to deploy.

For the route fallback, rename dist/index.html to vite.html before zipping: the static runtime answers every path that is not a file with vite.html, so reloading /about works. The steps are in the documentation's React tutorial.

The squarecloud.app configuration file is optional: the dashboard generates it at deploy time with the main file and memory, or you can write it yourself at the root of the project. Websites need at least 512 MB of RAM.

Every web application gets a *.squareweb.app subdomain with HTTPS, on every plan. A custom domain is available from Standard: you create the DNS records the dashboard shows at your registrar, and TLS is automatic. The domain stays registered in your name. Plans are billed in reais, and Hobby starts at R$12.49 per month. For more detail, see domains and site hosting.

Website hosting

Static and SSR sites with automatic TLS and a global CDN

Learn more

FAQs

Do I need a Node.js server to host a React app?

Not for a single-page app built with Vite. The build produces plain HTML, CSS and JavaScript that any static file server can deliver. You only need Node.js if you use server-side rendering (SSR).

Why does my React app return 404 when I reload a route?

Because the route only exists in the browser's JavaScript. The server looks for a file at that path, finds none and answers 404. The fix is to make the server return index.html for paths that are not files.

Can I keep API keys in React environment variables?

Not secret keys. Variables like VITE_API_URL are embedded in the build's JavaScript, and any visitor can read them. Keep secrets in a backend and expose only public values to the front end.

Is Create React App still a good way to start a new app?

It is not recommended. The React team deprecated it for new apps in February 2025. The React docs recommend a framework such as Next.js or React Router; to assemble your own project, use a build tool such as Vite.

Next articleWhat is web hosting and how does it work?Web hosting is an always-on server that stores your website's files and sends them to visitors. Learn how it works, the main types and what to check before you buy.

More in Websites

See all 20 articles