picking the right infrastructure for every app
The choice of platform for a React deployment decides build times, cost and control. Vercel, Netlify and a self-operated Docker stack solve the same problem with different trade-offs. This article shows concrete configurations, a CI/CD pipeline and the decision criteria for each situation.
Table of contents
- 1. Why the deployment strategy has to be decided early
- 2. Vercel: zero config deployment for Next.js and Vite
- 3. Netlify: build plugins, redirects and edge functions
- 4. Self-hosted with Docker and Nginx: full control
- 5. Static builds versus SSR deployment: infrastructure differences
- 6. CI/CD pipeline for automated React deployment
- 7. Preview deployments and branch deploys for code review
- 8. Rollbacks, health checks and zero downtime deployment
- 9. Cost comparison and decision criteria
- 10. Summary
- 11. FAQ
1. Why the deployment strategy has to be decided early
The React deployment question is often only taken seriously shortly before the first go live, yet the chosen platform already shapes the app's architecture decisions. A team that picks server side rendering with Next.js, then only later realizes the hosting has no Node runtime, ends up rebuilding the app for static rendering after the fact. A well planned React deployment therefore starts with the question of whether the app can be served purely statically or needs a server for every request.
The three common paths for a React deployment are managed platforms like Vercel and Netlify, plus self-operation via Docker and a custom reverse proxy. Managed platforms handle build, CDN distribution and SSL automatically, but cost noticeably more as traffic grows. Self-hosting hands back full control over infrastructure and cost, but demands in-house operational knowledge for certificates, scaling and monitoring. The following sections show all three paths with real configuration files.
The team itself also matters for the decision. A small team without a dedicated DevOps role usually benefits more from a managed platform than from the theoretical cost savings of a self-hosted setup. In the end, React deployment is always a trade-off between operational effort, cost and control, not a question of right or wrong.
2. Vercel: zero config deployment for Next.js and Vite
Vercel is built by the same team as Next.js and therefore offers the smoothest possible React deployment for Next.js projects. A git push to the connected branch automatically triggers a build, and every route is served as an edge function or a static page, depending on what the Next.js router requires. For Vite based React apps Vercel works just as well, detects the framework automatically and in most cases needs no additional configuration at all.
As soon as custom routing rules, redirects or specific headers are needed, the vercel.json file comes into play. This file controls the React deployment in fine detail without touching the application code itself. Particularly relevant are rewrites for single page applications, which must redirect every unmatched path back to index.html so that the client side router can take over.
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"rewrites": [
{ "source": "/api/(.*)", "destination": "https://api.mironsoft.de/$1" },
{ "source": "/(.*)", "destination": "/index.html" }
],
"headers": [
{
"source": "/assets/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
]
}
]
}
A common pitfall in React deployment on Vercel: environment variables prefixed with VITE_ or NEXT_PUBLIC_ get embedded at build time. Changing a variable in the Vercel dashboard therefore requires triggering a fresh build, a plain redeploy of the old build is not enough. Preview environments, the production environment and local development each allow their own variable values in Vercel, which makes staging tests considerably easier.
3. Netlify: build plugins, redirects and edge functions
Netlify follows a similar approach to Vercel but is more technology agnostic and suits any static React deployment, regardless of the build tool used. Configuration happens through netlify.toml in the project root, which has the advantage that deployment settings are versioned in the same repository as the application code.
Netlify build plugins extend the build process with additional steps, such as automatic Lighthouse checks after every build or image optimization before delivery. For a React deployment with strict performance requirements the @netlify/plugin-lighthouse plugin is worth adding, since it fails a build as soon as defined performance budgets are undercut.
# netlify.toml
[build]
command = "npm run build"
publish = "dist"
[build.environment]
NODE_VERSION = "20"
[[redirects]]
from = "/api/*"
to = "https://api.mironsoft.de/:splat"
status = 200
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[plugins]]
package = "@netlify/plugin-lighthouse"
[plugins.inputs.thresholds]
performance = 0.85
accessibility = 0.95
Netlify edge functions run, unlike classic serverless functions, directly at the edge location close to the user and are therefore well suited for A/B tests or geo redirects inside an otherwise purely static React deployment. The decisive difference from Vercel often lies less in the technology than in the pricing model, which teams with high bandwidth usage should compare carefully.
4. Self-hosted with Docker and Nginx: full control
A self-operated React deployment via Docker hands full control over infrastructure, networking and cost back to the team, but requires in-house knowledge of container orchestration in return. The usual approach uses a multi-stage Dockerfile build that first compiles the app with Node.js, then copies only the finished static files into a slim Nginx image.
This two-stage setup keeps the final image small, since Node.js, npm and the entire source code never become part of the production image. For React deployment into an existing Kubernetes cluster or onto self-managed servers this pattern is the standard, because the resulting image is only a few megabytes in size and starts within seconds.
# Dockerfile — multi-stage build for a React deployment
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:1.27-alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -q --spider http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]
The accompanying nginx.conf must contain one important rule for a React deployment: every unmatched path must fall back to index.html so the client side router can resolve the route itself. Without this rule Nginx returns a 404 on every direct call to a sub page, even though the route exists inside the React app. On top of that, gzip or brotli compression configured directly in Nginx is worthwhile, since most CDN platforms handle this automatically while a self-hosted React deployment must configure it explicitly.
5. Static builds versus SSR deployment: infrastructure differences
A purely client side React deployment built with Vite ultimately produces only static HTML, CSS and JavaScript files that any CDN or simple web server can serve. That makes self-hosting trivial and cheap, since no Node runtime has to run in production at all. Server side rendering with Next.js or Remix changes this equation fundamentally, because every request has to be answered by a running Node.js instance that renders React components into HTML at request time.
This need for a running runtime means that autoscaling, health checks and memory management suddenly matter for React deployment just as much as for any classic backend service. Vercel and Netlify abstract this away through serverless functions spun up per request, which can cause cold starts. A self-operated SSR deployment with Docker instead runs continuously, avoiding cold starts, but demands deliberate capacity planning for traffic spikes.
For many projects a hybrid approach pays off: marketing pages and blog articles get statically generated and served like a classic single page application, while genuinely dynamic, personalized areas run through SSR. This separation reduces server load for the React deployment considerably, without giving up the benefits of SSR for individually rendered pages.
6. CI/CD pipeline for automated React deployment
Regardless of the chosen platform, every React deployment should run through an automated pipeline that executes tests, linting and the actual build before every rollout. GitHub Actions is well suited for this, since it is directly tied to the repository and works both for Vercel deployments via the CLI and for self-hosted setups via Docker registries.
# .github/workflows/deploy.yml
name: React Deployment
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
- run: npm ci
- run: npm run lint
- run: npm run test -- --run
- run: npm run build
- name: Build and push Docker image
run: |
docker build -t registry.mironsoft.de/shop-frontend:${{ github.sha }} .
docker push registry.mironsoft.de/shop-frontend:${{ github.sha }}
- name: Deploy to production host
run: |
ssh deploy@prod.mironsoft.de \
"docker service update --image registry.mironsoft.de/shop-frontend:${{ github.sha }} shop-frontend"
The decisive advantage of such a pipeline for React deployment is that broken builds never reach production in the first place. If a test fails, the pipeline stops before any image is built or rolled out. This replaces manual deployment checklists with reproducible, versioned automation that every team member can rely on equally.
7. Preview deployments and branch deploys for code review
Vercel and Netlify automatically create an isolated preview environment with its own unique URL for every pull request. This fundamentally changes the review process for a React deployment, because reviewers no longer just read a change in a diff but can try it live in the browser before it gets merged. Design deviations, broken interactions or layout bugs surface far earlier this way than with plain code review without a preview.
For a self-hosted React deployment the same principle can be rebuilt with a bit more effort: a CI job builds its own Docker image per pull request and starts it under a subdomain pattern like pr-142.preview.mironsoft.de. Traefik or Nginx with dynamic configuration then handle the routing based on the branch name. The extra effort pays off especially in teams developing many frontend changes in parallel and wanting to regularly avoid visual regressions.
8. Rollbacks, health checks and zero downtime deployment
A production ready React deployment needs a fast way back if a release produces unexpected errors. Vercel and Netlify store every successful build and allow a rollback to an earlier version with a single click in the dashboard, without requiring a new build. This instant availability of past deployments is one of the biggest practical advantages of managed platforms.
#!/usr/bin/env bash
# rollback.sh — zero-downtime rollback for a self-hosted React deployment
set -euo pipefail
PREVIOUS_TAG="${1:?Usage: rollback.sh <previous-image-tag>}"
SERVICE="shop-frontend"
echo "[INFO] Rolling back $SERVICE to $PREVIOUS_TAG"
docker service update \
--image "registry.mironsoft.de/${SERVICE}:${PREVIOUS_TAG}" \
--update-order start-first \
"$SERVICE"
# Wait until the new task reports healthy before declaring success
until [ "$(docker service ps "$SERVICE" --filter "desired-state=running" -q | wc -l)" -gt 0 ]; do
sleep 2
done
echo "[OK] Rollback to $PREVIOUS_TAG completed"
For a self-hosted React deployment with Docker Swarm or Kubernetes, the start-first order is decisive: the new container must first be reported healthy before the old one is stopped. This is exactly what prevents downtime during the rollout. Health checks in the Dockerfile, as shown in the earlier example, give the orchestrator the information it needs to know whether a container can actually answer requests, rather than merely having started.
9. Cost comparison and decision criteria
The decision for a particular React deployment depends heavily on traffic volume, team size and regulatory requirements around data hosting. The table below summarizes the main differences and serves as a first orientation, but it does not replace an individual calculation.
| Criterion | Vercel | Netlify | Self-hosted (Docker) |
|---|---|---|---|
| Setup effort | Very low | Low | High, requires in-house operations knowledge |
| Preview deployments | Automatic per PR | Automatic per PR | Must be built yourself |
| Cost at high traffic | Rises noticeably with bandwidth | Rises noticeably with bandwidth | Predictable, fixed server cost |
| Data sovereignty | US provider, data processing agreement needed | US provider, data processing agreement needed | Full control, own location possible |
| SSR support | Native, optimized for Next.js | Good, a bit more configuration | Fully possible, more operational effort |
In practice, smaller teams and prototypes almost always reach their goal faster with Vercel or Netlify, because the React deployment requires no additional infrastructure work. As soon as traffic, compliance requirements or cost control become decisive, the balance increasingly shifts toward self-hosting with Docker, especially when a Kubernetes or Swarm cluster is already operated for other services anyway.
Mironsoft
React deployment, CI/CD pipelines and Docker infrastructure
Looking for the right deployment strategy for your React app?
We analyze your requirements around traffic, cost and data sovereignty and build a fitting React deployment pipeline, whether managed via Vercel and Netlify or self-hosted with Docker and Nginx.
Platform selection
Translating cost, SSR needs and compliance into a well founded decision
CI/CD setup
Automated pipelines with tests, preview deployments and a rollback strategy
Docker migration
Moving existing React apps onto a self-hosted, cost controlled setup
10. Summary
React deployment on Vercel or Netlify delivers the fastest result with the least operational effort, since build, CDN and SSL are fully managed. Both platforms offer automatic preview deployments per pull request and a one click rollback, which considerably eases day to day development. The price for this is rising cost at high traffic and a certain dependency on US based providers.
A self-hosted React deployment with Docker and Nginx requires in-house operations knowledge for health checks, zero downtime rollouts and certificate management, but hands back full control over cost and data sovereignty. For many projects the decision is not purely technical, it depends on team size, compliance requirements and long term cost planning. An automated CI/CD pipeline with tests before every rollout is always worthwhile, regardless of the chosen platform.
React Deployment: Vercel, Netlify and Self-Hosted at a Glance
Managed platforms
Vercel and Netlify handle build, CDN and preview deployments automatically. Ideal for small to mid-sized teams without a dedicated DevOps role.
Self-hosted with Docker
Multi-stage build, Nginx serving, health checks and zero downtime rollout give full control over cost and infrastructure.
CI/CD pipeline
Tests and linting before every build prevent broken releases from ever reaching production.
Rollback strategy
Keep earlier builds instantly available, whether via a dashboard click or a custom rollback script with a start-first order.