In the past, web applications used to be backend-centric, where HTML pages were generated on the server, and templates were used to add dynamic data.
As time passed, the demand for interactivity on web pages grew, leading to active advancements in frontend technologies, notably through the adoption of the Single Page Application (SPA) approach. Frameworks evolved to the point where the frontend became a separate application, designed and developed independently by separate teams and hosted separately as well.
This separation, while having its advantages, leads to several problems:
- The code sent to the browser becomes heavy and grows as the application's functionality increases.
- Much of the logic is moved to the client-side. For example, routing is implemented from scratch and bypasses browser mechanisms.
- Much of the logic is duplicated on the frontend and backend. For example, validation and access control.
- It's necessary to design and develop an API, an additional layer to synchronize frontend and backend, even where the backend only serves the interface.
- The division of specialists into frontend and backend developers in teams creates overhead costs, dilutes the understanding of the final task, and responsibilities.
However, the principles of how networks and browsers work have not changed: from the user's perspective, web services still appear as complete applications. Frameworks like Next.js are well-suited for such "holistic" development. Their capabilities were significantly limited until recently, but the latest versions of Next.js and React are changing the game.
React introduced server components, and Next.js implemented them along with a new approach to routing called App Router. Essentially, now some React components run on the client, while others run on the server, together forming a single web page. Server components can interact directly with the database, and the API layer becomes optional, replaced by Next.js routing mechanisms. It's now possible to create a full-fledged web application without a backend in the traditional sense. Nevertheless, of course, this does not mean that the backend is not needed at all times. On the contrary, the backend can now focus on its more backend-specific tasks without mixing them with presentation logic.
By shifting some of the frontend processing and rendering logic to the server-side, we can attain the following benefits:
- Accelerated initial page loading times, as the server can pre-render content before delivering it to the client.
- Enhanced search engine optimization (SEO).
- Mitigation of security risks associated with client-side code, as sensitive logic can be safeguarded on the server.
- Increased code reusability between frontend and backend components, streamlining the development process.
Interestingly, for instance, Ruby On Rails, primarily a backend framework, also pushes the boundary of separation, but in a slightly different way. Its authors propose Hotwire as an alternative to SPA, which involves decomposing and streaming individual parts of HTML.
Both approaches converge on one point: a significant portion of frontend logic is executed on the server, and we don't lose the benefits of SPA. Thus, the division between the client-side and server-side is not equivalent to the division between frontend and backend. Frontend is a part of the application responsible for interacting with the user and servicing that interaction, including on the server.
History is progressing in a spiral. More code is executed on the server again, but now we can build client applications of any complexity and beauty with less effort and fewer side effects.