A React app can look complete in a local preview and still fail the moment it reaches production. A missing environment variable, an incorrect build command, or a client-side route that returns a 404 can turn a polished release into a frustrating first impression. Knowing how to deploy a React app means preparing the project for the conditions it will face outside your machine.
The good news is that most React deployments follow a predictable path. Build optimized files, choose hosting that matches your app architecture, configure production settings, and verify the release as a real user would. The details matter, but the process does not need to be complicated.
Start by identifying what your React app needs Before choosing a deployment service, separate the frontend from the rest of the product. A standard React app built with Vite, Create React App, or a similar tool often produces static files: HTML, JavaScript, CSS, images, and fonts. Those files can be hosted on a static platform with a global content delivery network.
That approach works well for marketing sites, dashboards, prototypes, and web apps that call an external API or backend service. If your app uses Supabase, Firebase, Stripe, or another managed service, the React frontend can usually remain static while those services handle data, authentication, and payments.
The decision changes if your project needs server-side rendering, protected server endpoints, custom backend logic, or runtime access to secrets. In that case, you may need a framework and host that support server functions or a separate backend deployment. React itself is the interface layer, not a complete server architecture.
This distinction prevents a common mistake: trying to solve backend requirements by adding secrets to frontend code. Anything shipped to the browser can be inspected by users. Public API keys designed for browser use are fine. Private keys, database credentials, and payment provider secrets belong on a server or in protected functions.
Prepare a production build Your development server is designed for fast iteration, not production traffic. It includes tooling that helps you build and refresh locally. Deployment starts with generating the optimized files your host will serve.
For many Vite projects, the command is npm run build, and the output folder is typically dist. Older Create React App projects commonly use the same command but output to build. Check the project configuration instead of assuming the folder name. Your hosting provider needs both the build command and the correct publish directory.
Run the production build locally before you deploy. If it fails on your machine, it will fail in the deployment pipeline too. Build errors often expose unused imports, case-sensitive file path problems, or environment variables that were available locally but were never defined in the host.
It is also worth previewing the built version locally when your setup supports it. This catches differences between development behavior and the final bundled app, especially around asset paths and routing.
Keep dependencies and runtime versions predictable Commit your lockfile, whether that is package-lock.json, yarn.lock, or pnpm-lock.yaml. It gives the deployment environment a reliable record of the package versions that worked during development.
If your host lets you select a Node.js version, use the version your project expects. A deployment that works one week and breaks after a default runtime update is avoidable. Set the version deliberately in your project configuration or hosting settings.
Configure environment variables correctly Environment variables are where many first deployments go wrong. Your local .env file is generally not uploaded to source control or copied automatically to a deployment host. Add the required values in the host's environment variable settings, then trigger a fresh build.
Frontend build tools also have naming rules. Vite exposes browser-safe values that start with VITE_, while Create React App historically used REACT_APP_. A variable without the required prefix may exist during the build but remain unavailable in your client code.
Use separate values for local development, preview deployments, and production when the services differ. For example, a preview environment can point to a test database or a staging API, while production points to the live service. This makes it safer to test changes without affecting real users.
Do not treat environment variables as a vault if they are bundled into a React app. A frontend variable is visible in the delivered JavaScript. Use it for public configuration such as an API base URL or publishable client key, never for a secret that grants privileged access.
Choose a deployment workflow that supports iteration For most React projects, a Git-based workflow is the cleanest option. Connect the repository to a hosting provider, define the build command and output directory, then let each push create a deployment. Production can be tied to your main branch, while pull requests or feature branches create preview URLs for review.
Preview deployments are especially useful for product teams. A designer can review spacing and interactions in the browser. A founder can test an onboarding flow before it reaches customers. A developer can validate API changes against an isolated environment. Feedback happens against a working app, not a screenshot.
You can also deploy by uploading the generated build folder manually. This can be useful for a quick demo or a small project without source control. The trade-off is traceability: manual uploads make it harder to know exactly which code is live and harder to roll back cleanly. For an app that will keep evolving, automated deployments are usually the better default.
Sparkly can help shorten the path from a described product idea to a working project, but deployment still benefits from this same discipline: preview the real build, connect the services intentionally, and publish from a workflow you can repeat.
Handle client-side routing before launch A React single-page app may navigate perfectly through internal links but fail when someone refreshes a nested URL. For example, /settings/profile can show a 404 if the host looks for a physical file at that path instead of returning your app's index.html.
Configure a rewrite rule that sends unknown application routes to index.html. Your React router can then read the URL and render the correct page. Static assets should still be served normally, so use the platform's recommended single-page application fallback rather than a broad redirect that interferes with files.
Test this directly after deployment. Open a nested route in a new browser window, refresh it, and share it with someone else. If it fails, the routing fallback needs attention.
Verify the release beyond the homepage A successful build message only proves that the host created a deployable artifact. It does not prove that users can complete the job your app was built to do. Review the production version with a short release checklist:
Open the app in a private browser window to test the unauthenticated experience. Complete the core user flow, such as sign-up, checkout, form submission, or data creation. Refresh a nested route and confirm the page still loads. Check the browser console and network requests for failed assets, API errors, or blocked cross-origin requests. Test on a phone-sized viewport, not just a wide desktop screen. If authentication is involved, verify allowed redirect URLs in the auth provider. If the app calls an API, confirm that the production domain is permitted by the API's CORS settings. If payments are involved, use the appropriate test or live configuration for the environment. These are small setup details with outsized impact.
Add a custom domain and protect the next release A temporary deployment URL is useful during development, but a custom domain is part of the product experience. Add the domain through your host, update the required DNS records, and wait for HTTPS provisioning to complete. Once it is live, test both the root domain and the preferred www or non-www version so visitors are routed consistently.
Then think about the release after this one. Keep deployments tied to commits, use previews for changes that affect core flows, and retain a clear rollback path. Most modern hosts preserve previous deployments, which lets you restore a known working version quickly if a release introduces a regression.
Basic monitoring is worthwhile even for an early product. Watch for failed deployments, client-side errors, slow page loads, and API failures. You do not need a complicated operations stack on day one. You do need enough visibility to notice when a real user is having a different experience than your local preview.
A deployed React app is not a finish line. It is the first version users can respond to. Make each release repeatable, keep production configuration explicit, and let the feedback from a live product guide the next build.
