惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
Last Week in AI
Last Week in AI
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Cloudflare Blog
博客园 - 【当耐特】
博客园 - 叶小钗
量子位
博客园 - 聂微东
S
SegmentFault 最新的问题
美团技术团队
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
宝玉的分享
宝玉的分享
小众软件
小众软件
罗磊的独立博客
有赞技术团队
有赞技术团队
Stack Overflow Blog
Stack Overflow Blog

Graphite blog

Introducing Code Tours: a new way to review Introducing Cursor Cloud Agents in Graphite Building the future of software development with Cursor Reimagining the PR Page: Designing for speed and focus Graphite changelog [11-20-2025] Graphite changelog [11-04-2025] Graphite changelog [10-16-2025] The future of engineering is collaborative (and already here) Meet Graphite Agent: the next evolution of AI code review Introducing frozen branches: A safer way to build on your teammates’ work Graphite changelog [09-17-2025] How we sped up code search for Graphite Chat Introducing Graphite Chat AI is writing code—here's why it also needs to review that code How I got Claude to write code I could actually ship How we built the first stack-aware merge queue (and why it matters) How we organize our monorepo to ship fast Graphite brings stacking to Tower Code review tooling: Should you build or buy? Making AI code review available to everyone Introducing: The new Graphite + Linear integration Graphite raises $52M and launches Diamond to reimagine code review for the age of AI Why AI will never replace human code review How stacked PRs unblock distributed development teams Graphite is going to Developer Week 2025 Beating the end of year code freeze How Graphite’s eng team ships code remarkably fast Why we chose Anthropic's Claude to power Graphite Reviewer AI code generation will remain fragmented How we redesigned Graphite's landing page in-house
CRA to AppRouter in 5 Steps: A case study with Graphite
Kenneth DuMe · 2023-10-24 · via Graphite blog

At Graphite, we believe Next.js is the future. For anyone developing scalable, high-performance web applications, you need to migrate away from Create React App (CRA) and instead move to the Next.js framework.

Now, you may read this and think that sounds challenging. So did we, at first! Our codebase is structured in a sprawling, typescript monorepo, that dozens of developers collaborate on simultaneously. This made things a little more complicated, and our first attempts at migration were incredibly long, expensive, and failed partway through. However, after talking to members of the Vercel team, and using the new App Router, we condensed the entire migration into 5 simple PRs.

Before we tackle that though, let’s look at the difference between Next.js and CRA, and why we would even want to migrate in the first place.

What’s the difference between Next.js and a single-page application (SPA)?

There are two main differences between Next.js and single-page applications, such as those created by Create React App:

1. Rendering and data fetching:

Next.js supports multiple rendering strategies including server-side rendering (SSR), static site generation (SSG), incremental static regeneration (ISR), and client-side rendering (CSR). Depending on the specific page's needs, developers can choose whether to render at compile time, on the server, or in the browser.

On the other hand, Single-page applications built with Create React App are entirely client-side rendered: the application's content is rendered in the browser using JavaScript. The server sends a nearly empty HTML file, and JavaScript running in the browser fetches data and populates the page. This can increase latency and hurt page responsiveness as the JavaScript is downloaded, parsed, and executed.

2. Routing:

Because of this, the two also differ in how they handle routing. Next.js uses a file-system-based router built on App Router. By simply adding files to the 'pages' directory, routes are automatically available (and rendered by the selected strategy). Dynamic routing is also supported by creating files or folders with square bracket notation, e.g., pages/posts/[id].js.

Create React App on the other hand does not provide built-in routing. Instead, developers often integrate libraries like react-router to handle SPA-style navigation, where route changes do not trigger full page reloads but dynamically change page-contents based on the URL.

These two differences allow Next.js to optimize performance and improve developer experience in ways that just aren’t possible in a traditional single-page application model.

The benefits of Next.js over SPAs:

1. Bundle-splitting:

This is one of the biggest advantages with Next.js. Traditional single-page applications tend to send a large JavaScript bundle containing the entire application to the browser upon initial request. This can be inefficient, especially for large applications which need to parse and execute this code before first paint. Next.js however, automatically splits your codebase into smaller JavaScript bundles for each page, meaning that users only load the JavaScript necessary for the current page, greatly improving load times and overall performance.

2. Performance improvements:

Along with bundle-splitting, Next.js’s out-of-the-box optimizations like automatic image optimization, and smart prefetching, contribute to faster load times and overall user experience. Since Next.js supports both server-side rendering(SSR) and static site generation(SSG), it can deliver fully-rendered pages to the client, which can significantly improve perceived performance, especially on slower networks.

3. SEO and crawling:

We’re not the only ones who favor Next.js. Search engines also have an opinion. One historical downside of SPAs is the potential for SEO challenges, since not all search engine crawlers execute JavaScript effectively. With Next.js's server rendering capabilities, you deliver fully-rendered HTML content to crawlers, ensuring optimal indexing.

4. It's where web development is moving:

The web development landscape is rapidly evolving and new tools and frameworks are constantly emerging. Next.js is the latest in that category, offering increased flexibility, scalability, and performance improvements without adding much overhead. Backed by Vercel, Next.js has plenty of development resources behind it while at the same time enjoying the benefits of a strong community and ecosystem. It also seamlessly integrates with the JAMstack architecture, which is becoming the go-to for modern web development due to its scalability and performance benefits. More and more developers are moving to Next.js.

A journey in 5 pull requests

Knowing the differences between the two, let’s take a look at the 5 pull requests that made our migration possible.

1. HTTPS in local development:

The first problem we had was an API difference between react-scripts (the library CRA uses to power npm start) and Next.js. React-scripts has the flag HTTPS=true to serve content using HTTPS in local development. Unfortunately Next.js doesn’t have anything analogous, expecting you to use a third-party tool for that.

Following a stack overflow post, we adopted local SSL proxy. This allowed us to serve local host through  HTTPS, ensuring that our local development would remain unchanged.

2. SVG imports:

Create React App has a lot of built-in magic to allow you to import SVGs in JSX. Honestly it magically supports the import of all sorts of files, but the main one we cared about was SVGs. This was achieved using a specific configuration of the SVGr library which takes SVGs and converts them into react components. Unfortunately, Next.js doesn’t have this same support out of the box.

As a solution, in this PR, we imported SVGr and updated to its latest, recommended syntax that supports export as both a name component and as a default component. This entailed refactoring a handful of library imports but overall was a pretty small change.

3. Refactoring folder structure:

So this one is probably specific to us. As we mentioned above, Next.js has this awesome built-in routing functionality. Unfortunately, to support that functionality , Next interprets files in the “pages” directory as routes and assumes that they have specific exports.. While we did have a “pages” directory, they were not Next routes and did not have the required exports.

This PR renamed the directory “pages” to “router-pages”.

4. Integrating Next.js:

This next pull request (pun intended) is where the bulk of the migration took place; this is where the magic happens.

This pull request included a couple of different changes that I’m going to break out into a few steps.

Making Next work

First thing we had to do was introduce the next.config.js file to configure Next.

We didn’t do anything special with the configuration other than disabling static images. We did this because moving to Next’s image serving right now would require a pretty big amount of lift. We realized though we could split this out into an upstream PR later. So for now we turned this off.

The next thing we did was tweak our Webpack configuration; all we did here was update webpack to use the right SVGr version.

Furthermore, two new files, layout.tsx and page.tsx, were introduced. While layout.tsx replicated the layout previously defined in an index.html in CRA, page.tsx effectively took over what used to be in the app.js.

Development mode

Then because we’re coming from a single-page application, in the next.js config, we inject a rewrite, which says “hey for any page loaded, let’s just put you right at the index.” This allowed us to maintain our client-side routing pattern for the time being.

Git updates

So here we just updated out gitignore to ignore the .next folder, something we didn’t have to think about before

Tests

And finally we had to create a bunch of test mocks to handle file imports. You gotta have your tests

These changes enabled us to drop in Next.js; the package.json was updated to replace references of CRA (or in our case, Create React App rewired) with Next commands.

5. Handling server-side rendering (SSR):

The final PR was to handle server-side rendering or SSR. SSR introduces complexities when accessing objects like window and document. We added conditional checks before accessing objects exclusive to the browser environment. This prevented errors during server-side rendering (where JS might try to access window and run into window is undefined). 

Additionally, Next renders content on the server (for initial render) and on the client (for updates), and reconciles them through a process called hydration. If these two do’nt match, Next throws an error. Because React Router does not work on the server, we implemented an initial empty render for both server and client. This was a temporary solution to avoid hydration mismatches that we can remove after we migrate to Next’s routing.

Beyond these primary steps, we  also updated our Content Security Policy (CSP). Next.js injects inline scripts, which are disallowed under our CSP. We resolved this by adding a build step to hash all inline scripts.

We hope our little expedition showed you that migration to Next doesn’t have to be scary, and is well worth it. As we continue our development journey, we plan on fully integrating all the rest of what Next.js has to offer.