Skip to content
Back to Blog

Wednesday, September 19th 2018

Next.js 7

Posted by

After 26 canary releases and 3.4 million downloads, we are proud to introduce the production-ready Next.js 7, featuring:

Finally, we are excited to be sharing this news on the all-new Nextjs.org

DX Improvements

One of Next.js's primary goals is to provide the best production performance with the best possible developer experience. This release brings about many significant improvements to the build and debug pipelines

Compilation Speed

Thanks to webpack 4, Babel 7 and many improvements and optimizations on our codebase, Next.js now boots up to 57% faster during development.

Thanks to our new incremental compilation cache, changes you make to the code will now build 40% faster.

These are some example figures we have collected:

6.07.0delta
Bootup time (basic application)1947ms835ms57% faster
Code change (basic application)304ms178ms42% faster

As a bonus, when developing and building you will now see better realtime feedback thanks to webpackbar:

Better error reporting with React Error Overlay

Rendering accurate and help errors is critical to a great development and debugging experience. Until now, we would render the error message and its stack trace. Moving forward, we make use of react-error-overlay to enrich the stack trace with:

  • Accurate error locations for both server and client errors
  • Highlights of the source to provide context
  • A full rich stack trace

This is a comparison of the before and after of our errors:

The previous overlay left, react-error-overlay right
The previous overlay left, react-error-overlay right

As a bonus, react-error-overlay makes it easy to open your text editor by just clicking on a specific code block.

Webpack 4

Since its very first release Next.js has been powered by webpack for bundling your code and re-using the rich ecosystem of plugins and extensions. We're excited to announce Next.js is now powered by the latest webpack 4, which comes with numerous improvements and bugfixes.

Among these we get:

  • Support for .mjs source files
  • Code splitting improvements
  • Better tree-shaking (removal of unused code) support

Another new feature is WebAssembly support, Next.js can even server-render WebAssembly, here is an example.

Note: this upgrade is fully backwards-compatible. However, if you are using custom webpack loaders or plugins via next.config.js, you might have to upgrade them.

CSS Imports

With webpack 4, a new way of extracting CSS from bundles was introduced, called mini-extract-css-plugin.

@zeit/next-css, @zeit/next-less, @zeit/next-sass, and @zeit/next-stylus are now powered by mini-extract-css-plugin.

The new version of these Next.js plugins solves 20 existing issues related to CSS imports; As an example, importing CSS in dynamic import()s is now supported:

components/my-dynamic-component.js
import './my-dynamic-component.css';
 
export default function MyDynamicComponent() {
  return <h1>My dynamic component</h1>;
}
pages/index.js
import dynamic from 'next/dynamic'
 
const MyDynamicComponent = dynamic(import('../components/my-dynamic-component'))
 
export default function Index() {
  return () {
    <div>
      <MyDynamicComponent/>
    </div>
  }
}

A major improvement is that you are no longer required to add the following to pages/_document.js:

<link rel="stylesheet" href="/_next/static/style.css" />

Instead, Next.js automatically injects the CSS file. In production, Next.js also automatically adds a content hash to the CSS URL, so that if there are changes, to ensure that your end-users never get stale versions of the file and have the ability to introduce immutable permanent caching.

In short, all you have to do to support importing .css files in your Next.js project is to just register the withCSS plugin in your next.config.js:

const withCSS = require('@zeit/next-css');
module.exports = withCSS({
  /* my next config */
});

Standardized Dynamic Imports

Next.js has had support for dynamic imports through next/dynamic since Version 3.

As early adopters of this technology, we had to write our own solution for handling import().

As a consequence, Next.js was beginning to diverge from the support that webpack later introduced for it and some features were missing.

Because of this Next.js did not support a few import() features webpack has introduced since.

For example, naming and bundling certain files together manually was not possible:

import(/* webpackChunkName: 'my-chunk' */ '../lib/my-library');

Another example is using import() without being wrapped in the next/dynamic module.

Starting with Next.js 7 we no longer touch the default import() behavior. This means you get full import() support out of the box.

This change is fully backwards-compatible as well. Making use of a dynamic component remains as simple as:

pages/index.js
import dynamic from 'next/dynamic';
 
const MyComponent = dynamic(import('../components/my-component'));
 
export default function Index() {
  return (
    <div>
      <MyComponent />
    </div>
  );
}

What this example does is create a new JavaScript file for my-component and only load it when <MyComponent /> is rendered.

Most importantly, if it is not rendered, the <script> tag is not included in the initial HTML document payload.

To further simplify our codebase and make use of the excellent React ecosystem, in Next.js 7 next/dynamic was re-written to make use of react-loadable behind the scenes (with some minor modifications). This also introduces two great new features for dynamic components:

  • Timeouts using the timeout option on next/dynamic
  • A loading component delay, using the delay option on next/dynamic. This delay allows your loading component to wait x time before rendering the loading state, for example, if the import is very fast.

Babel 7

Next.js 6 introduced Babel 7 while it was still in beta. Since then the stable version of Babel 7 has been released, and Next.js 7 now using this version.

For a full list of changes, you can refer to Babel its release notes.

Some of the main features are:

  • Typescript support, for Next.js you can use @zeit/next-typescript
  • Fragment syntax <> support
  • babel.config.js support
  • overrides property to apply presets/plugins only to a subset of files or directories

If you do not have a custom Babel configuration in your Next.js project, there are no breaking changes.

If you do however have a custom Babel configuration, you have to upgrade the respective custom plugins/presets to their latest version.

In case you are upgrading from a version below Next.js 6 you can run the excellent babel-upgrade tool.

In addition to upgrading to Babel 7, the Next.js Babel preset (next/babel) now defaults to setting the modules option to commonjs when NODE_ENV is set to test.

This configuration option was often the only reason for creating a custom .babelrc in a Next.js project:

.babelrc
{
  "env": {
    "development": {
      "presets": ["next/babel"]
    },
    "production": {
      "presets": ["next/babel"]
    },
    "test": {
      "presets": [["next/babel", { "preset-env": { "modules": "commonjs" } }]]
    }
  }
}

With Next.js 7 this becomes:

.babelrc
{
  "presets": ["next/babel"]
}

At this point, the .babelrc can be removed, as Next.js will then automatically use next/babel when there is no Babel configuration.

Smaller Initial HTML Payload

As Next.js pre-renders HTML, it wraps pages into a default structure with <html>, <head>, <body> and the JavaScript files needed to render the page.

This initial payload was previously around 1.62kB. With Next.js 7 we've optimized the initial HTML payload, it is now 1.5kB, a 7.4% reduction, making your pages leaner.

6.07.0delta
Document size (server rendered)1.62kb1.50kb7.4% smaller

The main ways we have reduced size are:

  • The __next-error div is removed
  • The inline scripts are minified, in a future release they will be completely removed
  • Compiled away unused __NEXT_DATA__ properties when they are not used, for example, the nextExport and assetPrefix properties.

Static CDN Support

In Next.js 5 we introduced assetPrefix support, a way to make Next.js automatically load assets from a certain location, usually a CDN. This option works great if your CDN supports proxying, you request an URL like

https://cdn.example.com/_next/static/<buildid>/pages/index.js

Typically, the CDN checks if it has the file in its cache, or otherwise requests it directly from the origin.

Proxying assets is precisely how the Edge Network works.

However, some solutions require pre-uploading a directory directly into the CDN. The problem in doing this is that Next.js its URL structure did not match the folder structure inside the .next folder. For example our earlier example

https://cdn.example.com/_next/static/<buildid>/pages/index.js
// mapped to:
.next/page/index.js

With Next.js 7 we have changed the directory structure of .next to match the url structure:

https://cdn.example.com/_next/static/<buildid>/pages/index.js
// mapped to:
.next/static/<buildid>/pages/index.js

While we do recommend using the proxying type of CDN, this new structure allows users of a different type of CDN to upload the .next directory to their CDN.

Styled JSX v3

We are excited to introduce styled-jsx 3, the by default included CSS-in-JS solution in Next.js is now ready for React Suspense.

One thing that was often unclear was how to style a child component if that component is not part of the current component scope, for example, if you included a child component that needed specific styles only when used inside the parent component:

pages/index.js
const ChildComponent = () => (
  <div>
    <p>some text</p>
  </div>
);
 
export default function Index() {
  return (
    <div>
      <ChildComponent />
      <style jsx>{`
        p {
          color: black;
        }
      `}</style>
    </div>
  );
}

The above code tries to select the p tag does not work because styled-jsx styles are scoped to the current component, they do not leak into child components. One way to get around this was using the :global method, removing the prefix from the p tag. However, this introduces a new issue, which is that styles do leak across the page.

In styled-jsx 3 this issue has been solved by introducing a new API, css.resolve, which will generate the className and <style> tags (the styles property) for the given styled-jsx string:

pages/index.js
import css from 'styled-jsx/css';
 
const ChildComponent = ({ className }) => (
  <div>
    <p className={className}>some text</p>
  </div>
);
 
const { className, styles } = css.resolve`
  p {
    color: black;
  }
`;
 
export default function Index() {
  return (
    <div>
      <ChildComponent className={className} />
      {styles}
    </div>
  );
}

This new API allows for transparently passing through custom styling to child components.

Since this is a major release for styled-jsx, there is one breaking change that improves bundle sizes if you are using styles-jsx/css. In styled-jsx 2 we would generate a "scoped" and "global" version of external styles, even when only the "scoped" version was used we would still include the "global" version of those external styles.

With styled-jsx 3 global styles have to be tagged with css.global instead of css, so that styled-jsx can optimize bundle size.

For all changes, please refer to the release notes.

React Context with SSR between App and Pages

Starting from Next.js 7 we now support the new React context API between pages/_app.js and page components.

Previously it was not possible to use React context in between pages on the server side. The reason for this was that webpack keeps an internal module cache instead of using require.cache, we've written a custom webpack plugin that changes this behavior to share module instances between pages.

In doing so we not only allow usage of the new React context, but also reduce Next.js's memory footprint when sharing code between pages.

6.07.0delta
Memory usage57.5MB48.1MB-16% memory

nextjs.org

Together with the Next.js 7 release, we are launching a completely redesigned nextjs.org.

Blog

The blog post you are currently reading is already part of the new blog section on nextjs.org. This blog will be the new home for communication related to Next.js, for example, new version announcements.

The new nextjs.org
The new nextjs.org

Get Inspired

As the amount of apps using Next.js is continuously growing, we needed a way to show all these beautiful apps in one overview. Meet the new /showcase page:

Get inspired on nextjs.org/showcase
Get inspired on nextjs.org/showcase

This new showcase allows us to add new apps built with Next.js continuously.

We invite you to visit /showcase to get inspired, or submit your app that uses Next.js!

Community

Ever since it's first release Next.js has been used in everything from fortune 500 companies to personal blogs. We're very excited to see the growth in Next.js adoption.

  • Currently, there are over 12,500 publicly indexed domains using Next.js.
  • We've had over 500 contributors landing at least 1 commit.
  • On GitHub, the project has been starred over 29,000 times.
  • Almost 2200 pull requests were submitted since the first release.

The Next.js community has nearly 2000 members. Join us!