Nextjs

3 posts

toss4 min readCurated summary

The Monorepo Hope Edition: One Year to Bring a Despairing Repo Back to Hope

Toss argues that a monorepo alone does not guarantee a consistent or efficient frontend development experience. The real problem was dependency-version fragmentation across services, which made installations slow, platform changes risky, and upgrades difficult. Toss addressed this by introducing shared dependency “catalogs,” standardizing core libraries while preserving controlled, gradual upgrades. ## Toss’s Frontend Development Environment - More than 100 frontend engineers maintain products inside and outside the Toss app. - Despite the large number of products, services use nearly identical versions of React 19, Next.js 15, TypeScript, bundlers, and linters. - A shared monorepo makes it easier to: - Maintain a consistent development environment. - Share code across services. - Propagate platform-wide changes. - Give users access to features such as React Concurrent Mode and Server Components. ## Problems with an Unmanaged Monorepo - Services used widely different dependency versions, including outdated React and supporting libraries. - This created fragmented developer experiences: - Some services had fast development servers and modern APIs. - Older services were slower and harder to develop. - Dependency installation could take more than a minute even with caching. - Platform teams struggled to test shared libraries across many React and library versions. - Service developers avoided upgrades because compatibility risks and migration costs were high. - Older services consequently became locked into outdated dependencies. ## Why Toss Rejected a Polyrepo Strategy - Splitting the monorepo into separate repositories could reduce the size of each individual project and improve installation times. - However, polyrepos would not solve the main issues: - Development environments would remain fragmented. - Shared-code development and updates would become more expensive. - Differences between services could become even more pronounced. - Toss concluded that improving dependency management within the monorepo was preferable to abandoning it. ## Simplifying the Dependency Tree - The central issue was that services selected different versions of the same core libraries. - Toss identified roughly 10–20 commonly used libraries, including: - React - Component libraries such as TDS - Jotai - TypeScript - ESLint - Standardizing these dependencies could: - Reduce installation time. - Provide a consistent developer experience. - Make platform-library testing more predictable. - Enable automated migration scripts and compatibility layers. - Lower the cost of adopting breaking changes. - In practice, developers usually chose libraries rather than requiring specific versions, making centralized versions practical. ## Dependency Catalogs - Toss defined recommended versions as a shared **Catalog** using pnpm or Yarn workspace configuration. - Services reference catalog-managed dependencies with the `catalog:` protocol instead of specifying independent versions. - Named catalogs can support different release channels, such as: - `stable` - `beta` - Toss initially included essential dependencies such as React, Next.js, TypeScript, TDS, and the Toss App SDK. - Catalog packages had to be tested in representative service environments before release. - New services automatically referenced the latest catalog. - CI detected cases where developers accidentally bypassed catalog versions. - Existing services were migrated collaboratively with their code owners. - Catalog changes were released as new versions and rolled out gradually rather than modifying a shared version in place. - Upgrade scripts and AI Skills reduced the effort required to migrate services. ## Results After Full Adoption - Dependency duplication fell substantially: - `.pnp.cjs` shrank from 96 MB to 15 MB, an approximately 84% reduction. - Development-server startup improved from 26.7 to 20.3 seconds, about 23% faster. - Full dependency installation decreased from 528.4 to 249.9 seconds, about 52% faster. - Developers gained greater confidence that catalog packages had already been tested in real services. - Centralized version control reduced incompatible transitive dependencies, such as one package requiring version 1 while a service used version 2. - Better dependency visibility made large architectural improvements safer, including work involving RSC, TypeScript 7, Rspack, and end-to-end testing. - Services could adopt improved platform packages more consistently and with less upgrade friction. The practical recommendation is to retain the monorepo, but enforce a curated set of shared dependency versions through catalogs, CI checks, staged releases, and automated migration tooling. This combines the sharing benefits of a monorepo with a more predictable and maintainable development environment.

Read original(opens in new tab)
cloudflare4 min readCurated summary

How we rebuilt Next.js with AI in one week

Vinext is an experimental, Vite-based reimplementation of Next.js built in one week by one engineer and an AI model. It preserves much of Next.js’s API and project structure while avoiding the fragile process of adapting Next.js/Turbopack output for serverless platforms. Early results suggest builds can be up to 4× faster, client bundles up to 57% smaller, and Cloudflare Workers deployment can be handled with a single command. ## The Deployment Challenges of Next.js - Next.js provides an excellent developer experience but relies on a bespoke build and deployment toolchain. - Deploying to platforms such as Cloudflare, Netlify, or AWS Lambda requires reshaping Next.js output. - OpenNext addresses this problem but must reverse-engineer build artifacts, making it vulnerable to changes between Next.js versions. - Next.js’s planned adapters API improves deployment support but does not solve the underlying Turbopack dependency. - `next dev` runs only in Node.js, making it difficult to develop against platform-specific APIs such as Durable Objects, KV, and AI bindings. ## Vinext’s Vite-Based Architecture - Vinext reimplements the Next.js API surface directly on Vite rather than wrapping or adapting Next.js output. - Existing `app/`, `pages/`, and `next.config.js` files can be reused. - Developers install it with `npm install vinext` and replace `next` scripts with `vinext`. - It supports: - Routing - Server-side rendering - React Server Components - Server actions - Caching - Middleware - Hot module replacement - Vite’s Environment API allows the output to run across different platforms. ## Early Performance Results - Benchmarks compared vinext with Next.js 16 using the same 33-route App Router application. - Type checking and ESLint were disabled for Next.js to focus on compilation and bundling. - Static pre-rendering was disabled with `force-dynamic` for a fairer comparison. - Early results showed: - Production builds up to 4× faster - Gzipped client bundles up to 57% smaller - The results measure build performance, not serving performance, and come from a single test application. - The authors describe the figures as directional because both vinext and its supporting tools are still evolving. - Vite’s architecture and the upcoming Rust-based Rolldown bundler are identified as major sources of potential performance gains. ## Cloudflare Workers Deployment - `vinext deploy` builds the application, generates Worker configuration, and deploys it automatically. - Both the App Router and Pages Router are supported. - Applications retain client-side hydration, interactive components, navigation, and React state. - A Cloudflare KV cache handler provides Incremental Static Regeneration: ```ts import { KVCacheHandler } from "vinext/cloudflare"; import { setCacheHandler } from "next/cache"; setCacheHandler(new KVCacheHandler(env.MY_KV_NAMESPACE)); ``` - The cache layer is pluggable, allowing alternatives such as R2 or future Cache API improvements. - Because development and deployment can both run in `workerd`, applications can use Durable Objects, AI bindings, and other Cloudflare services without Node.js compatibility workarounds. ## Broader Ecosystem Potential - Although Cloudflare Workers is the initial target, roughly 95% of vinext is platform-independent Vite code. - Its routing, SSR pipeline, module shims, and React Server Components integration are not Cloudflare-specific. - A proof of concept reportedly ran on Vercel in under 30 minutes. - The project is open source and invites other hosting providers to contribute deployment targets. ## Experimental Status - Vinext is less than a week old and has not been tested under meaningful production-scale traffic. - The authors recommend caution before adopting it for critical applications. - Its test suite already includes more than 1,700 Vitest tests and 380 Playwright end-to-end tests, including tests ported from Next.js and OpenNext. - The project reportedly cost approximately $1,100 in AI-token usage to build. Vinext is best viewed as a promising experimental alternative rather than a drop-in replacement ready for every production workload. Teams interested in platform-native development and faster Vite-based builds can evaluate it carefully, while waiting for broader compatibility and real-world validation.

Read original(opens in new tab)
tossOriginal article

Creating Always-Up-To (opens in new tab)

Managing complex multi-page onboarding funnels often leads to documentation that quickly becomes decoupled from the actual codebase, creating confusion for developers. To solve this, the Toss team developed an automated system that uses static code analysis to generate funnel flowcharts that are never outdated. By treating the source code as the "Source of Truth," they successfully transformed hard-to-track navigation logic into a synchronized, visual map. ### The Limitations of Manual Documentation * Manual diagrams fail to scale when a funnel contains high-frequency branching, such as the 82 distinct conditions found across 39 onboarding pages. * Traditional documentation becomes obsolete within days of a code change because developers rarely prioritize updating external diagrams during rapid feature iterations. * Complex conditional logic (e.g., branching based on whether a user is a representative or an agent) makes manual flowcharts cluttered and difficult to read. ### Static Analysis via AST * The team chose static analysis over runtime analysis to capture all possible navigation paths simultaneously without the need to execute every branch of the code. * They utilized the `ts-morph` library to parse TypeScript source code into an Abstract Syntax Tree (AST), which represents the code structure in a way the compiler understands. * This method allows for a comprehensive scan of the project to identify every instance of navigation calls like `router.push()` or `router.replace()`. ### Engineering the Navigation Edge Data Structure * A "Navigation Edge" data structure was designed to capture more than just the destination; it includes the navigation method, query parameters, and the exact line number in the source code. * The system records the "context" of a transition by traversing the AST upwards from a navigation call to find the parent `if` statements or ternary operators, effectively documenting the business logic behind the path. * By distinguishing between `push` (which adds to browser history) and `replace` (which does not), the documentation provides insights into the intended user experience and "back button" behavior. ### Tracking Hidden Navigation and Constants * **Custom Hook Analysis:** Since navigation logic is often abstracted into hooks, the tool scans `import` declarations to follow and analyze logic within external hook files. * **Constant Resolution:** Because developers use constants (e.g., `URLS.PAYMENT_METHOD`) rather than raw strings, the system parses the project's constant definition files to map these variables back to their actual URL paths. * **Source Attribution:** The system flags whether a transition originated directly from a page component or an internal hook, making it easier for developers to locate the source of a specific funnel behavior. ### Conclusion For teams managing complex user journeys, automating documentation through static analysis is a powerful way to eliminate technical debt and synchronization errors. By integrating this extraction logic into the development workflow, the codebase remains the definitive reference point while providing stakeholders with a clear, automated visual of the user experience.