Next.js 9 was released six (6) months ago, followed by Next.js 9.1 three (3) months ago. These two releases added very powerful new features to Next.js, without increasing our baseline client runtime size.
Since then, we've focused heavily on refining and improving the framework as a whole: 9.1.1, 9.1.2, 9.1.3, 9.1.4, 9.1.5, 9.1.6, and 9.1.7. Let's dive into what these releases have improved!
- 3% – 8%+ Smaller Client-Side JavaScript Size: We've optimized application output even futher, shaving 7.5kB off hello world applications. More complex applications will show a savings up to 8% or more.
- Redesigned Production Build CLI Output: The production build output now shows gzipped file sizes in an easier to understand format.
- New Built-In Polyfills: fetch(), URL, and Object.assign: Applications can leverage the
fetch()
API,URL
, andObject.assign
in legacy browsers without compatibility concerns. - Optimized Page Loading: Better FCP and TTI: We've collaborated closely with the Google Chrome team to maximize page loading performance. This results in a much better end-user experience.
- Support for the Latest JavaScript Features: We're committed to ensuring you can always use the latest JavaScript features, including Optional Chaining, Nullish Coalescing, and other stable ES2020 features.
- Zero-Config Deployment Support for
next export
Applications:next export
powered applications can now be deployed to Vercel with zero configuration. - React Strict Mode Compliance and Opt-In: All of Next.js' client-side runtime is now compatible with React's Strict Mode. We've also added a configuration option to enable this mode for your whole application.
- Automated Testing against Nightly React Builds: Next.js is automatically tested against React's next channel, ensuring compatibility with future releases.
All of these benefits are non-breaking and fully backwards compatible. All you need to do to update is run:
In collaboration with the Google Chrome team, all Next.js applications will benefit from a 7.5kB or more size reduction.
Basic applications should see a 3-4% application size reduction, and more advanced applications may see upwards of 6-8% (or more)!
9.0.x | 9.1.x | delta | |
---|---|---|---|
Basic Application | 68.9kB | 66.1kB | 4.1%smaller |
These savings are partially attributable to
replacing the url
package's client-side version
with one built atop the URL API.
More size reduction has been accomplished by providing built-in, small polyfills for often-used packages. You can read more about those polyfills here.
Lastly, we've optimized our JSX output which will introduce savings in direct correlation to the amount of JSX in your application.
The CLI's production build output has been redesigned for clarity. Because Next.js is a hybrid application framework, each page may have different characteristics.
The new output classifies each page as one of the following:
- Server-Side Rendered (Server): the page server-side renders at runtime, meaning it uses
getInitialProps
orgetServerProps
(proposal) - Automatically Statically Optimized (Static): the page was rendered as static HTML at build time, and will be served as a static file (uses no initial props)
- Statically Generated Using Computed Data (SSG): the page was generated as static HTML/JSON at build time, and will be served as static files (uses
getStaticProps
(proposal))
Furthermore, the new output displays the Gzipped size of each page — these sizes exclude files that are shared by all pages (displayed separately).
Each page's size will be colored in accordance with their perceived user experience:
- Less than 130kB: Green — your application should be performant under most network and device conditions.
- Between 130kB and 170kB: Yellow — your application is nearing a 5-6 second load time on global baseline device + network conditions.
- More than 170kB: Red — your application will likely take more than 6 seconds to load on the same conditions.
We'd love to hear your feedback about the new build output.
In the near future Next.js will also have size budgets that help you ensure pages are within a certain size bracket.
While examining many users' applications and our examples, we found that most shipped with a similar set of polyfills. In some cases, applications even had duplicate polyfills for the same feature.
To remedy this, we collaborated with the Google Chrome team to build in polyfills for the three most common APIs we observed.
Using differential loading, these polyfills are not loaded for 83% of web traffic globally. This means that the majority of your users will not download the bytes associated with these polyfills—they'll only be downloaded if necessary.
Furthermore, any well-known polyfills that we've now built in will be completely eliminated from your production build. This means you will not pay the price for one of your dependencies that inadvertently import a polyfill for one of these APIs.
The list of built-in APIs and the polyfills they make obsolete are as follows:
- fetch() — Replacing:
whatwg-fetch
andunfetch
. - URL — Replacing: the
url
package (Node.js API). - Object.assign() — Replacing:
object-assign
,object.assign
, andcore-js/object/assign
.
You still need to import isomorphic-fetch
or isomorphic-unfetch
if you're
using fetch()
on the server.
This change is completely non-breaking, and all polyfills are made with the most spec-compliant versions available. The result is up to 18kB of JavaScript eliminated from your production bundles on modern browsers.
Next.js has optimized its preloading implementation to reduce FCP and overall TTI.
By working around a browser bug, CSS (when used) is now correctly prioritized over JavaScript. This results in a faster First Contentful Paint, resulting in a much faster visually complete website for your end-users.
Additionally, we've optimized our page prefetching to use lower-priority network requests. Furthermore, these requests only happen during browser idle-time, resulting in a quicker time-to-interactive. This is because the browser will prioritize making your application interactive over optimistic prefetching.
Next.js has an advanced, highly optimized compilation pipeline that allows you to use the latest JavaScript features. Recent optimizations we have introduced directly contributed to the 3-8% reduction in application size.
These JavaScript features can be leveraged without worrying about browser compatibility, as we automatically compile
your code to support all browsers (excluding end-of-life versions).
This includes ES6+ features, such as
async/await (ES2017),
Object Rest/Spread Properties (ES2018),
Dynamic import()
(ES2020),
and more!
In this release, we're happy to announce support for Optional Chaining (Stage 4) and Nullish Coalescing (Stage 4).
function Page(props) { return ( <p>{props?.deeply?.nested?.value}</p> /* ⬆ If deeply.nested.value is not available it won't render */ ) } export default Page
Optional chaining operator (?.
)
function Page(props) { return ( <p>{props.something ?? 'Default value'}</p> /* ⬆ results in "Default value" */ ) } export default Page
Nullish coalescing operator (??
)
In the future, we plan to output even more optimized bundles via automatic module / nomodule builds.
Next.js' next export
command now works with Vercel’s Zero Configuration out-of-the-box.
Prior to this change, users who leveraged next export
were required to create a custom now.json
.
Leveraging Next.js' export-mode on Vercel is as simple as having the following build
script in package.json
:
{ "scripts": { "build": "next build && next export" } }
Then, you can deploy your Next.js application to Vercel with only a single command.
If you have not yet installed Now, you can do so by installing Vercel CLI.
The complete Next.js runtime is now Strict Mode-compliant.
This included updates to Next.js' head manager (<Head>
), next/dynamic
, and other core features.
This means the runtimes now leverage hooks or have eliminated deprecated lifecycles,
and are using React's new Context API.
We've also added a convenient opt-in option for you to enable Strict Mode for your application.
To do so, configure the following option in your next.config.js
:
// next.config.js module.exports = { reactStrictMode: true }
If you or your team are not ready to use Strict Mode in your entire application,
that's OK!
You can incrementally migrate on a page-by-page basis
using <React.StrictMode>
.
While not required, Strict Mode will unlock a lot of optimizations in the future. Because of this, we suggest you look into it sooner rather than later!
In close collaboration with the React Core Team, we're now testing Next.js against React's next channel every 12 hours.
These tests help ensure we're prepared and compatible with the future releases of React. Compatibility is something Next.js takes very seriously, and we're committed to the long-term API stability of Next.js.
This process has been documented by the React Core Team in hopes other projects in the React ecosystem follow suit.
We are excited about the upcoming changes that will improve size and performance across all Next.js applications.
Furthermore, the Next.js community is still expanding:
- We have had over 865 independent contributors.
- On GitHub, the project has been starred over 43,700 times.
- The examples directory has over 220 examples.
The Next.js community now has over 13,600 members. Join us!
We are thankful to our community and all the external feedback and contributions that helped shape this release.