Abhinav Anshul
16 Nov 2022
•
8 min read
NextJS recently released version 13, which introduces a lot of new features and patterns that overhauls how we have been writing Nextjs-based applications and React code in general. This release was focused on improving Next's internal tooling as well as incorporating React 18 into NextJS, along with some big improvements on file-based routing that Next prefers over Component based routing
In this post, you will learn about all the new features and changes that were added to the NextJS version 13 announced at Next Conf very recently.
NextJS is betting big on Server Components. If you have been catching up on React version 18, you might already be familiar with how React components now have the ability to render themselves as both Client & Server side Components.
NextJS 13 takes this concept ahead and introduces Server Components by default under the new app
directory. You might be familiar with pages
folder, where you define all your routes and NextJS uses this file-based routing(instead of component-based) for generating URLs. Well, in somewhat near future, the pages
folder will be deprecated and app
directory will be used by default(you will learn about this in the next section).
The file-based routes defined under this new app
directory will be React Server Components by default. But first, you need to understand what's the difference b/w these two, that is Client-Side components & Server Components.
Traditionally, React has always been a Client-side unopinionated view library, although if you wanted to serve the React App as the Server side, you could spin it up against an express-like server. However, after NextJS introduced server-side rendering methods such as getStaticPath
, getServerSideProps
etc, it became quite obvious that SSR-based pages perform much better and are beneficial in the long run. It removes all those network latency issues, where end-users have to typically wait for an API to fetch data and in that time frame, they are stuck with annoying Loaders/Spinners.
Therefore, taking all those inspiration and developer experience in general, the NextJS team has shipped React Server Components by default. When those pages will be rendered, the server will only send prefetched HTML
only content and very minimum javascript. This ensures improved caching and better performance. React Server Components also help in eliminating all those data fetching React hooks and NextJS methods like getServerSideProps()
, getStaticProps()
, getInitialPath()
etc. You will learn more about this in the next section.
NextJS version 13 has completely changed the way of fetching data in your React apps. If you have been working with Next for quite some time, then you might be familiar with the data fetching methods like getServerSideProps()
, getStaticProps()
, getInitialPath()
etc as we also have talked about these earlier. Starting NextJS 13, these methods are considered an anti-pattern and hence deprecated to use.
Instead, NextJS 13 emphasizes fetching data only on the server-side, and not using hooks such as useEffect()
whatsoever to fetch data on the client side.
Fetching data on the server has a lot of benefits including and not limited to : You can keep your sensitive data like API keys, hash functions, staging/dev URLs, etc, on the server and it would remain secure and won't be leaked anywhere to the end-user on the client side. You are doing fewer communication protocols between the client and server, as the server would send pre-rendered content to the client. This improves performance. A very noticeable change is having fewer loaders/spinners as the pages would be generated beforehand. The server can fetch data from different APIs then only it would be sent to the client, saving network calls on the Client side
Using React Server Components, you can save a lot of your trouble by using plain old fetch()
Web API and passing it along the props wherever you need it. Since everything would be generated on the server, the page where you have passed your props won't be generated at all until the API response has been registered.
async function getDataFrom API() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/');
return response.json();
}
async function Home() {
const user = await getDataFrom API();
return(
<div>{user}</div>
)
}
export default Home
The given component would work smoothly as this component would be generated on the server and sent to the client. you don't need to fetch any API on the client side.
However, there could be certain cases where you really need a component on the client side. Cases, where you are using React hooks, changing state values right on the UI, giving feedback to the end users, etc. In all these cases, you can use, use-client
notation right on top of a React Component. It would let NextJS know, you want this to be rendered on the client side only.
apps
the new pages directoryOne of the most talked about change in the NextJS ecosystem is the introduction of a new app
directory. While you can still create a good old pages
directory and can set up all your pages in it but while doing so, you will miss out on all the latest and exciting features offered by NextJS version 13.
NextJS version 13 offers a new app
directory for setting up your pages and hence all your routes. All the pages defined in the app
directory will be SSR only and you have to explicitly mention use-client
to use it on the client side as we discussed earlier.
The basic features of app
directory are somewhat similar to that of the pages
folder as,
app (directory)
dashboard(folder)
> Content.jsx (file)
> Analytics.jsx (file)
The above folder structure created under the new app
directory would still map to the following URL as expected and the same as the old pages
directory-
localhost:3000/dashboard/content (renders the Content.jsx file)
localhost:3000/dashboard/analytics (renders the Analytics.jsx file)
however, the app
directory has made things pretty interesting by introducing special files, you can either put these special files in the root folder itself (in our case outside the dashboard folder) or route-wise/folder-wise.
These special files are :
page.tsx
- This component file is unique to every route and should be created if you want this route to be publically accessible.
layout.tsx
- This component file could be a generic Layout file like the one you create at the root that further contains Header, Footer components. Layout file would preserve its state and won't re-render its UI while its children states can continue to do so.
loading.tsx - This one is an optional file and can be used to conditionally render a loading state for a section of the page.
error.tsx - Similar to loading.tsx
, this special file can be used to render a part of a page to conditionally render your error state, if a condition can be met, this error would be resolved.
template.tsx - This one is very similar to layout.tsx
file but this one is not optimized for performance, hence it doesn't store and cache state and re-render every time, unlike the layouts file.
head.tsx - You might have stored all your meta tags in the React component itself, under the <head></head>
tags, well this file separates that logic and you can put those meta tags here as well.
NextJS version 13 is at par with React version 18. It introduces one of the best features of React18 to its workflow, which is Streaming. In typical SSR pages, you usually have to wait for the entire page to be generated on the server, only then you can see it getting rendered on the screen. Of course, this can be easily fixed by introducing client-side rendering and generating a page section by section as the data gets fetched from the server. But, Client side rendering introduces another problem of lots of loaders, spinners, poor end-user experience, and so on.
You can solve this issue in SSR pages only by using Streaming. React server components would start "streaming" & sending data as soon as something is generated on the server, by this technique your end user would not have to wait for a longer period, but they would start seeing some skeleton or basic UI until the entire page loads. You can think of this behavior as similar to how client-side rendering behaves but in this case, it is SSR pages sending data to the client using Streaming.
Starting with version 13, NextJS uses this concept in their new app
directory. As you already know from the points discussed above, the new app
directory would generate SSR pages by default. You can use "stream" your page by using the Suspense APIs as,
<Suspense fallback={<p>Loading User Dashboard...</p>}>
<Dashboard />
</Suspense>
In the code above, although the Dashboard component won't be generated until it receives data from the server until then React will suspend the component rendering and would render the Loading User Dashboard
instead. You can also replace this simple text with a more complex UI or a skeleton screen, and once you have data from the server, the UI would be auto-populated by Suspense API. This pattern is of course better than server-side rendering but also improves a lot on typical NextJS SSR pages.
There are a few surface APIs that are being improved in the NextJS version 13 :
Image Component: If you have worked with NextJS, you know that the Image
component is the defacto API for rendering images and is preferred over the native img
tag. In NextJS 13, the Image
component would ship less javascript to the client side and has some performance improvements.
@next/font: NextJS 13 is shipping their own font system. It would automatically optimize your font for better rendering performance and good First Contentful Paint(FCP) score by using font-display
and various other properties & strategies. you can use it as,
import { Lato } from '@next/font/google';
const lato = Lato();
<main className={lato.className}>
// app
</main>
Just make sure the fonts are publically available on Google Fonts, as @next/font
uses it to fetch it from there internally.
<Link/>
API as well. NextJS 13 makes it easier to use the Link
tag, and it is no longer recommended to use the <a />
tag underneath the wrapping Link
tag, instead, NextJS would automatically adjust itself.You might have heard about Webpack, it is an asset bundler that takes in a bunch of different files like HTML, JavaScript, image & video assets and spits out a javascript bundle. Webpack has been dominant in the React ecosystem for a long time.
Chances are, you might have heard about the ever-popular create-react-app
, that React template uses Webpack for JavaScript bundling. Webpack is certainly great, however over time, the JavaScript ecosystem has developed bundlers that are much smaller in size and more efficient than Webpack. Turbopack is one such bundler.
Going forward, NextJS version 13 is officially replacing its Webpack bundler with Turbopack. Turbopack embraces Rust based future and hence its core is written in Rust itself. By many standards, Turborepo surpasses Webpack in bundling.
On the high level, you have nothing to worry about how NextJS will bundle your files internally and things would be the same on the surface for NextJS developers, just a little fast and reduction in compilation time overall.
That being said, you have now covered almost everything there is to learn about the new NextJS version 13. In this article, you learned about the new architectural principles that version 13 offers and looked at that new app
directory that is set to replace the pages
directory in the future. Also, saw the various changes that is been done in the NextJS internal tooling, the most prominent being, moving away from Webpack to Turbopack for JavaScript bundling.
NextJS version 13 in general offers a lot of good web standards going forward. It ensures that Server Side Rendering practices can be paired quite well with Client-side rending. These sure are exciting times ahead for React and our web ecosystem!
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!