React + Vite
An interactive browser app connected to an existing or separate API.
React · Vite · TypeScript · your API
Complete guide (Markdown) · Structured record (JSON)
Original source review: 2026-10-10. Core guidance rechecked: 2026-10-13. Check scope. Dependency combinations and setup need project-specific qualification.
Use cases
- Interactive dashboards
- API-backed browser tools
- Client-rendered applications
Choose it when
- Backend/identity already have owners
- SSR is not a product requirement
- Browser UI and API can be deployed independently
Consider another path when
- Searchable server-rendered content is central
- The task requires native device UI
- Team expects the frontend scaffold to supply backend auth or persistence
Working practices
- Keep credentials, SQL access and authorization behind the API. Browser validation does not establish permission.
- Keep strict TypeScript and validate API responses where data crosses trust boundaries.
- Choose a router and server-state cache only when navigation and data complexity need them.
- Test production asset paths and direct navigation to nested routes. Offline use needs explicit storage, synchronization and conflict rules.
Tools by job
browser build and UI: React + Vite + TypeScript
Focused browser development without unnecessary server framework
TypeScript compiles to JS; Vite is tooling, not a backend; keep HTML/CSS competence
validation: Zod at API/client boundaries
Check external values and share explicit contracts
Client checks never replace authoritative backend validation or authorization
Identity ownership: Existing backend owns authentication and authorization
Avoid duplicating external-system ownership in browser code
No database credentials/server secrets in browser; document API/session/CORS contract
Database ownership: Existing backend owns persistence and migrations
Avoid duplicating external-system ownership in browser code
No database credentials/server secrets in browser; document API/session/CORS contract
Background work ownership: Existing backend owns durable jobs
Avoid duplicating external-system ownership in browser code
No database credentials/server secrets in browser; document API/session/CORS contract
Static typing: Strict TypeScript; retain generated project-reference build
Static checks and user-visible browser behavior
Configure router/API failure/session expiry tests; preserve scaffold-specific build scripts
Linting: ESLint
Static checks and user-visible browser behavior
Configure router/API failure/session expiry tests; preserve scaffold-specific build scripts
Domain and component tests: Vitest
Run isolated domain behavior checks with a configured test environment
Install Vitest; preserve Vite plugins or add a separate test configuration. Mock only external boundaries and test failure states.
Browser tests: Playwright
Exercise critical journeys in actual browser engines
Install @playwright/test and matching browsers; configure an isolated test server/data and test session expiry, routing and authorization failures.
deployment: Static asset host chosen by project
Browser build can be independently served
Configure deep-link fallback, API origins, cache invalidation and environment handling; preview is not production
Server state cache: TanStack Query for client-owned remote state
Queries, mutations and invalidation support interactive API screens
Install @tanstack/react-query and provide QueryClient. Define tenant-aware keys, staleTime/retry policy and clear session data on sign-out; in Next prefer server loading until a client cache has a job.
Forms: React Hook Form for complex client forms
Separates client form state and validation from page components
Install react-hook-form only where needed; wire existing runtime schemas deliberately. Render accessible labels/errors; validate and authorize submissions on the server.
Styling: Tailwind CSS when utility styling fits the project
Reusable styling without a runtime component dependency
For Vite install tailwindcss and @tailwindcss/vite, add the plugin and CSS import. Use the framework-specific installation path for Next; retain established styles when present.
Accessible UI primitives: Radix Primitives for complex controls
Provides focus and keyboard behavior for common interaction patterns
Install only used components. Authors still supply names, contrast and meaningful composition; verify keyboard and assistive-technology behavior.
Accessibility checks: axe-core through Playwright + manual keyboard review
Automated audits identify common accessibility defects in real pages
Install @axe-core/playwright; scan representative states and use a screen reader/keyboard. Passing automated rules is not complete accessibility evidence.
Routing: TanStack Router
Typed navigation, route loading and search parameters suit application screens
Install @tanstack/react-router; configure the chosen file-based plugin or code-based routes. Test deep links, not-found routes and browser back; route guards do not replace server authorization.
Live server updates: EventSource for one-way server events
Browser-standard streaming suits status/progress feeds
Backend owns authenticated stream and event IDs. Test reconnect, replay and proxy buffering; EventSource is one-way and its constructor offers no arbitrary authorization-header option. Confirm long-lived connection support on host.
Build with the stack’s strengths
Architecture and developer workflow.
React/Vite builds browser assets. Recommendation: select it when an existing API owns persistence, authorization, email, durable jobs and other privileged effects; choose routing and remote-state tools deliberately. A client-only build has no protected server runtime.
Version scope: Documentation reviewed 11 October 2026: current React docs label 19.3; current Vite docs include migration from v7 and Rolldown build options. Preserve the project's resolved React/Vite/TypeScript/router versions and API schema. SPA guidance is not a claim that Vite supplies SSR or a backend. · Reviewed 2026-10-11
Architecture boundaries
- Views consume route-loaded or query-cached DTOs; one API client module defines credentials, errors, cancellation and runtime validation. Backend ownership remains independent of UI language.
- Recommendation: domain state stays on the server; transient form/navigation state stays in the browser. Use tenant-aware cache keys and an explicit account-switch/reset policy.
- Bundled VITE_ values are public configuration. Keep database, provider and signing credentials in the backend; a development proxy is only local routing.
- Recommendation: retain content-hashed old chunks during rollout, revalidate HTML and provide a guarded update path for stale tabs. Add service-worker storage/adoption policy only if offline operation is required.
Tools and feedback
- Start at the source README, API schema and lockfile. For a new local prototype npm create vite@latest my-app -- --template react-ts creates a starter; record resolved versions before promoting it. Existing applications keep their package manager.
- Use npm ci, the configured TypeScript project check (for the standard scaffold npx tsc -b) and npm run build. npm run dev is local development; npm run preview previews a build and is not the production host.
- Configure routing, typed API boundaries, TanStack Query only where useful and its QueryClientProvider. Define loading, stale, denied and offline states before using retries.
- Recommendation: use browser network/debug tooling and React profiling for the actual slow interaction. Configure Playwright with old/new API fixtures; run npx playwright test only after installing its runner/browsers and setting an isolated webServer.
Translations to avoid
- Bundling a secret as VITE_API_KEY publishes it to users; moving its string into a frontend module does not create a trust boundary.
- Rebuilding server authorization as React route guards allows direct unauthorized API calls.
- Independent fetching in nested effects creates waterfalls and duplicated state ownership; use route loaders or a selected remote-state cache where appropriate.
- Treating TanStack Query defaults as an application freshness contract overlooks refetch/retry behavior and account boundaries.
- Deleting old chunks on deployment breaks lazy imports in open tabs; repeated automatic reload can also discard unsaved work.
For an existing application
Keep the contracts while you change the stack.
These are documented options and proposed checks. Inspect the actual source application before adopting a transition.
Browser and installed clients
Inspect the source
Existing URLs, backend API DTOs, errors, permissions and navigation/deep-link semantics.
During coexistence
Recommendation: Replace one route/screen with React while keeping existing API ownership and deep links; contract fixtures cover old/new UI.
Target design
Recommendation: Keep a browser/API split with route loaders or a selected query client; adopt a server framework only when required rendering/backend features justify it.
Rollback
Restore old HTML/assets/routes while API compatibility remains; preserve submitted data and reconcile pending mutations.
Benefits and prerequisites
An independently delivered browser client can evolve behind a stable API.
Requires: Owned routing/hosting fallback and backward-compatible API.
Tradeoffs: A SPA must own routing/data/loading infrastructure; SSR/RSC are additional architecture choices.
Checks before transfer
- Direct deep links and refresh work from the production host.
- Old/new clients decode success/error/unknown-field fixtures.
- Unauthorized direct API requests remain denied.
Identity and authorization
Inspect the source
Backend credential transport, allowed origins, cookies/CSRF, token expiry and account boundaries.
During coexistence
Recommendation: Keep the backend issuer; configure same-origin routing or narrowly allowed credentialed CORS and preserve old clients.
Target design
Recommendation: Centralize credential/error behavior in the API client; enforce authorization and any cookie CSRF protection in the backend.
Rollback
Restore the old browser artifact/origin policy only if existing credential handling remains secure; retain revocation history.
Benefits and prerequisites
One backend authority reduces duplicated browser identity logic.
Requires: Reviewed origin/credential policy and issuer behavior.
Tradeoffs: CORS controls browser response access, not authorization; frontend guards remain presentation only.
Checks before transfer
- Credentialed requests succeed only for permitted origins.
- Expired credentials transition to sign-in without endless retries.
- Cross-tenant and CSRF probes are rejected by the backend.
Caching and shared state
Inspect the source
Current fetch/cache behavior, stale tolerance, retry limits and account-switch isolation.
During coexistence
Recommendation: Introduce query keys for a bounded remote-state category; keep transient form state separate and compare outcomes with the old fetch path.
Target design
Recommendation: Use explicit TanStack Query staleTime, retry, invalidation and account-clear policy where its remote-state cache serves a requirement.
Rollback
Return the category to the old loader and clear the new cache; do not discard durable pending user operations.
Benefits and prerequisites
Shared queries can reuse data and refresh deliberately.
Requires: A QueryClientProvider, stable tenant-aware keys and mutation invalidation.
Tradeoffs: Default stale queries refetch on mount/focus/reconnect; retries can obscure application errors if left unspecified.
Checks before transfer
- A mutation refreshes affected list/detail views.
- Switching accounts cannot reuse the old account's records.
- Network restoration produces one coherent refresh; permission errors do not retry indefinitely.
Realtime transport
Inspect the source
Existing event envelope, authorization, IDs, reconnect behavior and replay/retention rules.
During coexistence
Recommendation: Keep a backend bridge producing the current event contract; move clients by stable subscription cohort rather than arbitrary per-request routing.
Target design
Recommendation: Use EventSource for one-way events when host/credentials fit, WebSocket for bidirectional needs; persist/replay events separately when delivery requires it.
Rollback
Restore old polling/transport using the same cursor domain; reconcile delivered events and keep bridge/history through the rollback window.
Benefits and prerequisites
A standard browser event stream can replace bespoke polling for suitable feeds.
Requires: Authenticated endpoint, event IDs, retention/replay contract and streaming host.
Tradeoffs: EventSource reconnect does not create server event history; its constructor has no arbitrary header option.
Checks before transfer
- Disconnect after event N and reconnect; no required event is omitted or applied twice.
- Revocation terminates access and later reconnect is denied.
- Old/new envelopes decode during mixed-version rollout.
Delivery and recovery
Inspect the source
Existing HTML/CDN/service-worker policy, lazy chunks and open-tab unsaved state.
During coexistence
Recommendation: Keep prior hashed assets and compatible APIs while serving new HTML to a cohort; include any existing service worker's activation/cache rules.
Target design
Recommendation: Revalidate HTML, retain old content-hashed chunks and handle vite:preloadError with a guarded refresh/update flow that preserves drafts.
Rollback
Restore the prior HTML and retained assets, roll service-worker changes through their actual lifecycle, and keep new-client API support.
Benefits and prerequisites
Old tabs can continue loading their release's lazy chunks.
Requires: Asset retention, correct base path and tested update UX.
Tradeoffs: Retention costs storage; refresh may lose state, and reload loops do not fix a wrong CDN policy.
Checks before transfer
- After deployment an old tab lazy-loads its old route successfully.
- If a chunk is intentionally unavailable, the update path retains the draft and recovers once.
- Production HTML/cache headers and API compatibility match the rollout policy.
Setup
- Start in repository parent in a local development workspace with API/session owners identified.
- Run npm create vite@latest my-app -- --template react-ts; enter my-app; npm install; record resolved versions and commit lockfile.
- Create README with API contract, run/check instructions and environment variable names. Configure strict TypeScript and router/query tooling only as needed.
- Add Zod and test tools; configure request validation, error/loading/session-expiry states and authoritative backend authorization tests.
- Build to static assets, configure chosen host deep-link behavior and API origins, then run production browser checks.
Verification
Run these in the configured application; they are instructions, not recorded passes.
npm ci npx tsc --noEmit npx eslint . npx vitest run npm run build npx playwright test
Open questions
- Which API and identity owner defines schemas, cookies/tokens and CORS?
- Do routes need shareable URLs, offline behavior or server rendering?
- Which browser/device matrix and accessibility requirements must be met?
- Which static host supports route fallbacks and the selected API origins?
Sources
- Vite getting started
- TanStack Start
- Zod
- Next.js authentication
- Next.js Vitest
- Next.js Playwright
- React TypeScript
- TanStack Query important defaults
- React Hook Form repository
- Tailwind Vite installation
- Radix accessibility
- Playwright accessibility testing
- TanStack Router overview
- HTML EventSource standard
- Vitest guide
- Playwright installation