React consulting and front-end architecture

React is a rendering library, not an architecture. Most of the trouble we are called in to fix comes from the decisions React deliberately leaves to you — state, data fetching, rendering strategy — being made implicitly.

Overview

React has become the default for enterprise front-end work, largely because of hiring availability and ecosystem breadth rather than because it is technically dominant. That is a legitimate reason and it shapes what goes wrong.

What React deliberately does not decide is the interesting part: state management, data fetching, routing, rendering strategy and how components are composed. Those decisions get made anyway, usually implicitly and differently in each part of an application.

Our work here is mostly architectural: establishing rendering strategy against real requirements, deciding where state lives, and treating accessibility and performance as requirements rather than as a later pass. Both are considerably cheaper to build in than to retrofit.

Enterprise use cases

Where we see this used to good effect, and what makes each case a fit.

Customer-facing web applications

Where interaction complexity justifies a component-based front end and hiring availability makes the team sustainable.

Internal tools and admin consoles

Data-dense interfaces where component reuse across many screens pays back quickly.

Design systems and component libraries

A shared component layer across products, where consistency and accessibility are enforced once rather than per team.

Content-led sites needing interactivity

Where server rendering serves the content and React handles the parts that genuinely need to be interactive.

Progressive replacement of legacy interfaces

Replacing an older front end screen by screen rather than in a single cutover the business cannot absorb.

Accessibility-critical interfaces

Public sector and education services where conformance is an obligation and the component layer is where it is enforced.

Architecture

The decision with the widest consequences is rendering strategy: client rendering, server rendering or static generation, chosen against real requirements for first paint, interactivity and search visibility rather than by framework default.

The second is where state lives. Applications that put everything into a global store make simple changes expensive; applications with no strategy at all end up with the same data fetched independently in six places, each with its own loading and error handling.

  • Rendering strategy chosen against first paint, interactivity and search requirements
  • Server state and client state distinguished, since they need different handling
  • Component boundaries drawn for reuse rather than mirroring the page layout
  • Routing and code splitting designed together, not added when the bundle grows

Best practices

The practices that keep a React codebase workable are mostly about constraint. TypeScript throughout rather than partially, a component library used rather than bypassed, and a stated position on which patterns the codebase uses.

The most valuable and least glamorous is treating the component library as the only way to build UI. Where teams can drop to bespoke markup when convenient, accessibility and visual consistency both degrade steadily and nobody notices until an audit.

  • TypeScript applied throughout, since partial adoption gives false confidence
  • The component library made the easy path, or it will be bypassed
  • A stated position on state management rather than several coexisting approaches
  • Linting and formatting automated so they never become review conversations

Security

React escapes rendered content by default, which removes the most common injection class — until someone reaches for the escape hatch that injects raw HTML, which is where most front-end injection vulnerabilities we find originate.

The larger issue is architectural: what the front end is trusted to enforce. Authorisation implemented only in the client is not authorisation, and hiding a control does not restrict the endpoint behind it.

  • Raw HTML injection treated as prohibited rather than reviewed case by case
  • Authorisation enforced server-side, with the client treated as untrusted
  • Tokens stored with the trade-offs understood rather than by convention
  • Dependencies pinned and scanned, given the size of front-end dependency trees

Scalability

Front-end scalability is mostly about the codebase rather than traffic. Large React applications become slow to build, slow to test and difficult to change when boundaries were never drawn.

Where multiple teams contribute, the question is how to allow independent delivery without fragmenting the user experience. Micro-frontends solve a real problem and introduce substantial complexity, and they are adopted more often than the problem warrants.

  • Module boundaries drawn so build and test time stay tolerable as the codebase grows
  • Independent team delivery weighed against user experience fragmentation
  • Micro-frontends adopted only where independent deployment is a genuine requirement
  • Shared design system governing consistency regardless of the delivery model

Performance

Front-end performance is a commercial property in consumer contexts and an accessibility one everywhere: a slow interface excludes people on older devices and constrained networks, which in India is a large share of users.

The dominant costs are bundle size and unnecessary re-rendering. Both are measurable, both are addressable, and both are usually assessed on a developer's machine on a fast connection — which is the least representative environment available.

  • Measured on representative devices and networks, not on a developer machine
  • Bundle size budgeted and enforced in the build rather than reviewed occasionally
  • Re-render behaviour profiled before optimisation is attempted
  • Images, fonts and third-party scripts treated as first-order performance costs

Integration

The integration that matters most is with the API layer, and the recurring problem is a front end shaped around endpoints that were designed for a different consumer — producing many round trips to assemble one screen.

Where the front end cannot change the API, caching and request coalescing help. Where it can, designing the interface around what the screen actually needs is usually the larger win and is frequently not attempted.

  • API shape designed for the screens that consume it where that is possible
  • Server state handled by a caching layer rather than by hand in components
  • Loading, error and empty states designed as part of the interface, not added later
  • Contract and versioning agreed with the API owner rather than assumed stable

Operations

Front-end operations centre on release and observability. Client-side errors are invisible without deliberate reporting, and an application failing for a subset of browsers or devices can do so for weeks without anyone knowing.

Deployment is comparatively simple, and the property worth designing is the ability to roll back quickly — front-end regressions are highly visible and the fastest remedy is almost always reverting.

  • Client-side error reporting with enough context to reproduce a failure
  • Real user performance measured, not only synthetic tests at build time
  • Rollback fast and verified, since front-end regressions are immediately visible
  • Browser and device support stated explicitly and tested against

Governance

The governance that matters is the design system. Where it is genuinely the easiest path, consistency and accessibility hold across teams; where it is a recommendation, both degrade steadily and the drift is only visible in aggregate.

Accessibility governance belongs here too. Automated checks in the pipeline catch a meaningful portion, and the rest requires manual assessment — so the standard should state which is expected of whom rather than implying the scan is sufficient.

  • The design system made the path of least resistance, not a recommendation
  • Accessibility checks automated in the pipeline, with manual review defined too
  • Dependency updates automated where the test suite makes it safe
  • A stated browser and device support matrix, tested rather than assumed

Frequently asked questions

Decided against requirements rather than by default. Server rendering helps first paint and search visibility; client rendering suits applications behind a login where neither matters much. Most applications need a considered mix, and the mistake is inheriting the framework's default without asking.

Start by separating server state from client state — they have different requirements and conflating them is the root of most state complexity we see. Server state wants caching and invalidation; client state is usually small enough that elaborate tooling is unnecessary.

Bundle size and unnecessary re-rendering, measured on representative devices and networks rather than on a developer machine. That last point matters more than it sounds: the development environment is the least representative one available, particularly for users on older devices.

Probably not. They solve a real problem — independent deployment by separate teams — at substantial cost in complexity and user experience consistency. They are adopted considerably more often than that problem is actually present.

Through the component library, so accessibility is built once rather than per screen, combined with automated checks in the pipeline and manual assessment for what automation cannot catch. Retrofitting accessibility into a delivered application is materially more expensive than building it in.

Yes, applied throughout. Partial adoption is the trap: it gives an impression of safety the type checker cannot actually provide, because it cannot reason about the untyped portions and reports silence rather than uncertainty.

Usually yes, screen by screen behind consistent routing and a shared design language. That is nearly always preferable to a cutover: it delivers value earlier and each increment can be assessed rather than the whole thing being judged at the end.

Only as a user experience convenience. Hiding a control does not restrict the endpoint behind it, and authorisation implemented only in the client is not authorisation. The server must enforce it independently, treating the client as untrusted.

First ask whether the API shape is right — a screen requiring six round trips usually reflects endpoints designed for a different consumer. Where the API can change, that is the larger win. Where it cannot, caching and request coalescing help materially.

Because client-side failures are invisible without deliberate reporting. An application broken for a particular browser or device can fail that way for weeks with no signal at all, which is why error reporting with enough context to reproduce is worth setting up early.

Yes, through software development, and we also take architecture and review engagements where your team builds and we assess rendering strategy, state design and accessibility.

Next step

Discuss a front-end architecture

A free first consultation covering your rendering strategy, where state lives, and whether the performance and accessibility position would survive measurement on a real device.

No cost, no obligation. Pricing is transparent and includes GST.