# React + Vite

An interactive browser app connected to an existing or separate API.

React · Vite · TypeScript · your API

[Complete guide (Markdown)](/stacks/typescript-react-vite-browser/guide.md) · [Structured record (JSON)](/stacks/typescript-react-vite-browser/record.json)

Original source review: 2026-10-10. Core guidance rechecked: 2026-10-13. [Check scope](/research-freshness.json). 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

- [https://vite.dev/guide/](https://vite.dev/guide/)

- [https://tanstack.com/start/latest](https://tanstack.com/start/latest)

- [https://react.dev/learn/typescript](https://react.dev/learn/typescript)

### validation: Zod at API/client boundaries

Check external values and share explicit contracts

Client checks never replace authoritative backend validation or authorization

- [https://zod.dev/](https://zod.dev/)

### 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

- [https://nextjs.org/docs/app/guides/authentication](https://nextjs.org/docs/app/guides/authentication)

### 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

- [https://nextjs.org/docs/app/guides/authentication](https://nextjs.org/docs/app/guides/authentication)

### 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

- [https://nextjs.org/docs/app/guides/authentication](https://nextjs.org/docs/app/guides/authentication)

### 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

- [https://vite.dev/guide/](https://vite.dev/guide/)

- [https://nextjs.org/docs/app/guides/testing/vitest](https://nextjs.org/docs/app/guides/testing/vitest)

- [https://nextjs.org/docs/app/guides/testing/playwright](https://nextjs.org/docs/app/guides/testing/playwright)

### Linting: ESLint

Static checks and user-visible browser behavior

Configure router/API failure/session expiry tests; preserve scaffold-specific build scripts

- [https://vite.dev/guide/](https://vite.dev/guide/)

- [https://nextjs.org/docs/app/guides/testing/vitest](https://nextjs.org/docs/app/guides/testing/vitest)

- [https://nextjs.org/docs/app/guides/testing/playwright](https://nextjs.org/docs/app/guides/testing/playwright)

### 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.

- [https://vitest.dev/guide/](https://vitest.dev/guide/)

### 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.

- [https://playwright.dev/docs/intro](https://playwright.dev/docs/intro)

### 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

- [https://vite.dev/guide/](https://vite.dev/guide/)

### 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.

- [https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults)

### 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.

- [https://github.com/react-hook-form/react-hook-form](https://github.com/react-hook-form/react-hook-form)

### 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.

- [https://tailwindcss.com/docs/installation/using-vite](https://tailwindcss.com/docs/installation/using-vite)

### 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.

- [https://www.radix-ui.com/primitives/docs/overview/accessibility](https://www.radix-ui.com/primitives/docs/overview/accessibility)

### 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.

- [https://playwright.dev/docs/accessibility-testing](https://playwright.dev/docs/accessibility-testing)

### 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.

- [https://tanstack.com/router/latest/docs/overview](https://tanstack.com/router/latest/docs/overview)

### 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.

- [https://html.spec.whatwg.org/multipage/server-sent-events.html](https://html.spec.whatwg.org/multipage/server-sent-events.html)

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.

[react.dev →](https://react.dev/learn/build-a-react-app-from-scratch)
[vite.dev →](https://vite.dev/guide/)
[vite.dev →](https://vite.dev/guide/env-and-mode)
[vite.dev →](https://vite.dev/guide/build)
[vite.dev →](https://vite.dev/guide/static-deploy)
[tanstack.com →](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults)
[fetch.spec.whatwg.org →](https://fetch.spec.whatwg.org/)
[html.spec.whatwg.org →](https://html.spec.whatwg.org/multipage/server-sent-events.html)

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.

[react.dev →](https://react.dev/learn/build-a-react-app-from-scratch)
[vite.dev →](https://vite.dev/guide/static-deploy)

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.

[fetch.spec.whatwg.org →](https://fetch.spec.whatwg.org/)
[vite.dev →](https://vite.dev/guide/env-and-mode)

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.

[tanstack.com →](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults)

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.

[html.spec.whatwg.org →](https://html.spec.whatwg.org/multipage/server-sent-events.html)

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.

[vite.dev →](https://vite.dev/guide/build)
[vite.dev →](https://vite.dev/guide/static-deploy)

[Read the migration workflow →](/rewrite/guide.md)

## 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](https://vite.dev/guide/)

- [TanStack Start](https://tanstack.com/start/latest)

- [Zod](https://zod.dev/)

- [Next.js authentication](https://nextjs.org/docs/app/guides/authentication)

- [Next.js Vitest](https://nextjs.org/docs/app/guides/testing/vitest)

- [Next.js Playwright](https://nextjs.org/docs/app/guides/testing/playwright)

- [React TypeScript](https://react.dev/learn/typescript)

- [TanStack Query important defaults](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults)

- [React Hook Form repository](https://github.com/react-hook-form/react-hook-form)

- [Tailwind Vite installation](https://tailwindcss.com/docs/installation/using-vite)

- [Radix accessibility](https://www.radix-ui.com/primitives/docs/overview/accessibility)

- [Playwright accessibility testing](https://playwright.dev/docs/accessibility-testing)

- [TanStack Router overview](https://tanstack.com/router/latest/docs/overview)

- [HTML EventSource standard](https://html.spec.whatwg.org/multipage/server-sent-events.html)

- [Vitest guide](https://vitest.dev/guide/)

- [Playwright installation](https://playwright.dev/docs/intro)

---

Canonical page: https://stack.menu/stacks/typescript-react-vite-browser/
