Frontend Development 25 min read

Modern.js: Integrated Full‑Stack Development and Server‑Side Capabilities

This article introduces Modern.js, a ByteDance‑initiated open‑source framework that unifies frontend engineering and server‑side development by offering a minimal core, integrated web server, plugin system, and progressive full‑stack features to simplify routing, rendering, API handling, and deployment for modern web applications.

ByteDance Web Infra
ByteDance Web Infra
ByteDance Web Infra
Modern.js: Integrated Full‑Stack Development and Server‑Side Capabilities

1. Opportunities and Responsibilities of Modern.js

At the 2021 Rare Earth Developer Conference, ByteDance Web Infra officially launched the Modern.js open‑source project and gave its first public introduction.

On January 7, 2022, at the 10th Global Software Case Study Summit, Kong Jiacong presented "Full‑Stack Web Development Practices at ByteDance," focusing on Modern.js’s server‑side capabilities and benefits. This article is the written version of that talk.

Hello, I am Kong Jiacong from ByteDance Web Infra. Our department builds a "Web technology platform" and develops a "frontend R&D system".

In October 2021, ByteDance Web Infra officially started the Modern.js open‑source project and introduced it for the first time.

In that presentation we popularized the modern web development paradigm and explained the capabilities and benefits Modern.js provides under this new paradigm.

1.1 The New Era of JavaScript Brings Opportunities

Two industry trends support the emergence of Modern.js.

First, with the rise of Serverless, frontend developers are moving toward full‑stack development. While this is exciting, many developers still have strong frontend knowledge but weaker server‑side expertise.

https://css-tricks.com/ooooops-i-guess-were-full-stack-developers-now/

This confirms the need for a framework that further assists frontend developers in building full‑stack applications.

Second, JavaScript has entered a new phase often called the "third age of JS," marked by a new wave of tooling updates.

https://www.swyx.io/js-third-age/

Frameworks now have clearer responsibilities, leading to tool consolidation (e.g., Deno combines testing, linting, and bundling). This trend allows Modern.js to provide a complete solution within a limited scope.

1.2 Responsibilities and Vision of Modern.js

A complete application needs both a UI framework and a Node.js CLI plus a server‑side runtime. The former handles engineering tasks, the latter hosts the built assets and request logic.

Integrating CLI functionality and developing server‑side features is cumbersome and often non‑reusable across different app types.

Modern.js aims to hide these complexities so developers can focus on product development, even in full‑stack scenarios.

We strive for a progressive framework: developers can start with no Modern.js features (CSS‑in‑JS, TypeScript, routing, SSR) and simply import src/App.jsx to run in development and production.

When more complex needs arise, developers can add solutions within the framework, achieving a "1 + 1 > 2" effect, while still being able to fall back to custom implementations if needed.

Modern.js consists of a minimal core, an integrated web server, and a comprehensive plugin system. It offers three "standard engineering solutions" that can be customized by adding or replacing plugins.

Almost all capabilities are implemented via plugins, and any functionality exposed to built‑in plugins can also be used in custom plugins.

2. Common Server‑Side Requirements for Web Applications

We have introduced why Modern.js exists, its vision, and design philosophy. Next, we examine typical server‑side requirements of web applications and how Modern.js addresses them.

2.1 Web Server

A Web Server is needed to run the application locally or in production. Locally developers often use webpack‑dev‑server ; in production they use Node.js frameworks such as Express or Koa.

2.1.1 Entry and Routing

Routing is the most common server requirement. In multi‑page applications each entry should have an independent route.

Typical needs include custom route prefixes, per‑entry routes, serving the same entry via different routes, shared routes with different request conditions (e.g., user‑agent ), route‑specific response headers, and dynamic server‑side routes.

Entries can also be SPA pages, requiring the server to correctly match SPA routes, handle single‑entry multiple routes, dynamic routes, and maintain consistency as the application evolves.

2.1.2 Pre‑Execution and Isomorphism

Beyond basic routing, the industry trend is to execute code as early as possible: compile‑time, then server‑side, and finally in the browser (SSG/SSR/CSR).

In SSR, concerns include data reuse, rendering consistency, and library coordination (Helmet, Loadable, styled‑components) across environments.

To support runtime downgrade (e.g., when QPS exceeds a threshold), SSR and CSR must be interchangeable, with fast switching and performance optimizations such as streaming, caching, and edge rendering.

SSG involves combining compilation and rendering, isolating runtime data, and handling mixed rendering scenarios.

2.1.3 Generic Services and Custom Logic

Web applications also have generic server‑side needs such as UA‑based polyfills, delivering different JavaScript bundles, micro‑frontend injection, i18n injection, authentication, parameter preprocessing, route redirection, and bot blocking.

2.2 API Services

Many internal tools and admin apps require dedicated API services, often implemented as BFF functions or full Node.js APIs.

Key considerations include development vs. production execution, integration with the Web Server, hot‑reloading, API design, parameter validation, response schema, optimal request mechanisms (in‑process, internal IP), WebSocket support, and GraphQL (Apollo) integration.

2.3 Application Deployment

Deployment is another server‑side concern. Modern web optimization often relies on platform‑level capabilities.

2.3.1 One‑Click Preview

One‑click preview is essential for feature comparison, acceptance testing, bug tracing, etc., requiring parity between local, preview, and production deployments and automatic preview link generation.

2.3.2 Deployment Optimization

When the deployment platform can recognize artifacts (Web, SSR, API) and split them, each part can be deployed to the most suitable container, improving security and stability.

Collaboration between the framework and platform is needed for artifact tagging and request forwarding.

3. Integrated Development in Modern.js

Many frontend developers lack strong server‑side expertise, making full‑stack development difficult. Modern.js is designed to simplify server‑side logic for them.

3.1 Automatic Routing

Modern.js generates routing protocols based on entry directory structure and configuration files. The server matches incoming requests to the correct handling logic using these protocols.

Routing protocols can resolve multiple routes to the same HTML, define header‑based matching, and compute the correct basename for SPA consistency.

3.1.2 Routing Mode Switching

Modern.js supports both single‑page and multi‑page applications, file‑based and code‑based routing. Switching between modes requires only minor entry file changes, eliminating extensive configuration and boilerplate.

3.2 Unified Rendering

Modern.js provides isomorphic APIs for both server and browser.

3.2.1 Isomorphic Rendering

All APIs are isomorphic. For example, the useLoader hook behaves like useEffect on the client but reuses SSR/SSG data on the server.

Developers can toggle between CSR and SSR by changing server.ssr configuration, and enable compile‑time rendering by setting output.ssg .

3.2.2 On‑Demand Rendering

SSR/SSG flags are stored in the routing protocol, allowing per‑entry rendering decisions. The Node.js CLI reads the protocol to perform compile‑time rendering where appropriate, while the server selects the optimal runtime logic for other pages.

3.2.3 Mixed Rendering

Modern.js supports global SSG/SSR and local CSR, enabling static rendering for fixed headers and client‑side rendering for dynamic lists. Future work includes more complex mixes and Server Components.

3.3 Front‑Back Integration

API calls can be made like normal function imports from the api/ directory. The framework auto‑generates APIs based on BFF function paths and parameters, handling network details transparently.

Shared type definitions provide full linting and autocomplete, while the framework selects the best request method.

Modern.js enforces a standard function signature for BFFs to keep routes compatible with RESTful APIs and avoid private protocols.

Type schemas enable runtime parameter validation and standardized responses.

3.3.2 Progressive API Services

Initially an app may need only a single function to aggregate data. As requirements grow (e.g., authentication), developers can add middleware hooks. For larger projects, the framework can launch a full‑featured API service using Egg capabilities.

3.3.3 Custom Web Server

Modern.js’s built‑in server handles common needs such as static asset distribution and UA‑based polyfills via simple configuration or plugins.

For non‑generic needs, developers can add custom middleware in server hook files, enabling features like permission checks and redirects.

3.4 Pluggable Application Structure

Modern.js makes api/ and src/ directories pluggable, allowing applications to expand from Node.js to full‑stack or extract API services for independent deployment without major restructuring.

4. Business Scenarios

The previous sections described how Modern.js addresses server‑side requirements. Below are real internal use cases at ByteDance.

4.1 Rendering Cache

For a high‑traffic SSR feature called "Hot Events," traffic spikes can cause cold‑start latency. By adding rendering cache code, the application intercepted most traffic, reducing cold‑start impact and cutting required instance count by 90%.

4.2 Replacing SSR with SSG

The ByteDance website originally used SSR with a custom data cache. After a DDoS attack, the team switched to SSG combined with CMS webhooks and V8 workers, achieving at least a 20‑fold increase in QPS while keeping the editorial workflow unchanged.

4.3 Custom Engineering Solutions

On the Volcano Engine platform, applications often need to modify project structure or support multiple deployment targets (overseas, domestic, separate deployments). Modern.js’s abstraction and plugin system enable rapid adaptation without major code changes.

4.4 Other Scenarios

Some teams previously built SSR services with Go, incurring heavy configuration and maintenance overhead. Migrating to Modern.js required only code migration, dramatically improving development efficiency.

Across all these scenarios, adding a small amount of Modern.js code yields significant benefits.

We will continue to open more Modern.js features to the community. Join the Modern.js community group or visit the official website for more information.

Thank you.

backendfrontendServerlessIntegrationWeb DevelopmentFull-StackModern.js
ByteDance Web Infra
Written by

ByteDance Web Infra

ByteDance Web Infra team, focused on delivering excellent technical solutions, building an open tech ecosystem, and advancing front-end technology within the company and the industry | The best way to predict the future is to create it

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.