Next.js, the popular web application development framework, has recently announced the release of its latest version: Next.js 14. During the fourth annual Vercel conference, the Next.js developers presented a series of improvements and new features that promise to make the framework even more powerful and user-friendly.
Unlike previous versions that focused on adding new APIs, Next.js 14 distinguishes itself by its dedication to refining existing tools, providing developers with a more efficient and intuitive solution for building modern web projects.
In this article, we’ll explore all the significant features of this new version of the full-stack framework built on React, examining the motivations behind their introduction and how we can implement them in our applications.
Recommended video: Let’s build a Modern react application!
Turbopack: A Turbo Compiler for Next.js
One of the most significant additions in Next.js 14 is the introduction of Turbopack, an innovative compiler that replaces Webpack. Built on the Rust programming language, this new system promises to revolutionize the development process with local server startup times 53.3% faster and code updates 94.7% faster, thanks to Fast Refresh. Turbopack is a substantial leap forward in local development performance, providing tangible speed and reliability benefits.
To test Turbopack immediately:
Ensure you have version 14 of Next.js in your project. You can update it by modifying the dependency in your package.json file and then running npm install
or yarn install
.
In some versions of Next.js 14, Turbopack might not be enabled by default. If necessary, you can enable it by adding a flag to your start command. For example, you could modify your dev script in package.json from “dev”: “next dev” to “dev”: “next dev –turbo”.
Server Actions: Simplifying Data Mutations
Next.js 14 introduces Server Actions as a stable feature, simplifying web application development significantly. Server Actions allow you to define functions executed on the server that can be invoked directly by React components on the client side. This approach makes data mutations easier, enhancing the user experience in scenarios with slow connections or less powerful devices. Developers can now implement server-side features more intuitively, reducing code complexity and improving efficiency.
Server Actions are deeply integrated into the entire App Router model. You can:
- Revalidate cached data with
revalidatePath()
orrevalidateTag()
. - Redirect to different routes using
redirect()
. - Set and read cookies through
cookies()
. - Handle optimistic UI updates with
useOptimistic()
. - Capture and display server errors with
useFormState()
. - Show loading states on the client with
useFormStatus()
.
Here’s an example:
```javascript
// app/page.tsx
export default function Page() {
async function createItem(formData) {
'use server';
// Logic to create an item (e.g., save to the database)
return { success: true };
}
// Rest of the component…
}
Code language: PHP (php)
In the same component, you can now use this function directly to perform server-side actions, such as responding to a form submission:
// Continued in app/page.tsx
export default function Page() {
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const result = await createItem(formData);
if (result.success) {
// Handle the success of the action
}
}
return (
{/* Form elements */} Submit
);
}
Code language: JavaScript (javascript)
Here, the createItem
function is executed on the server when the form is submitted. This approach allows handling server-side operations such as data saving or other backend processing efficiently and securely, directly within React components.
Here’s an example of how you might structure a Next.js 14 component containing two forms, each interacting with different Server Actions using GET and POST methods:
Defining Server Actions in External Files:
// actions/getData.js
export async function getData() {
'use server';
// Logic to retrieve data (GET)
}
// actions/postData.js
export async function postData(formData) {
'use server';
// Logic to send data (POST)
}
Code language: JavaScript (javascript)
Creating the Component with Two Forms:
// app/page.tsx
import React from 'react';
import { getData } from '../actions/getData';
import { postData } from '../actions/postData';
export default function Page() {
async function handleGetSubmit(event) {
event.preventDefault();
const result = await getData();
// Handle the response
}
async function handlePostSubmit(event) {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const result = await postData(formData);
// Handle the response
}
return (
<div>
<form onSubmit={handleGetSubmit}>
{/* Form elements for GET */}
<button type="submit">Get Data</button>
</form>
<form onSubmit={handlePostSubmit}>
{/* Form elements for POST */}
<button type="submit">Post Data</button>
</form>
</div>
);
}
Code language: JavaScript (javascript)
Partial Prerendering: Combining Static and Dynamic
Another experimental feature in Next.js 14 is Partial Prerendering. This function aims to combine the benefits of static site generation (SSG) and server-side rendering (SSR). Using React Suspense component boundaries, Partial Prerendering determines which parts of the application are static and which are dynamic. Static parts are prepared as HTML, while dynamic parts are updated only when necessary. This hybrid approach promises to simplify development by offering the performance of staticity with the flexibility of dynamic content.
To implement Partial Prerendering in Next.js 14, you will use React Suspense features to define which parts of your application can be statically prerendered and which need to be loaded dynamically. Here’s an example:
Use Suspense to define the dynamic parts of your component that should be loaded after the static shell is loaded:
// app/page.tsx
import React, { Suspense } from 'react';
const DynamicComponent = React.lazy(() => import('./DynamicComponent'));
export default function Page() {
return (
<div>
<h1>Static Title</h1>
<Suspense fallback={<p>Loading...</p>}>
<DynamicComponent />
</Suspense>
</div>
);
}
Code language: JavaScript (javascript)
Define the component that will be loaded dynamically:
// DynamicComponent.tsx
export default function DynamicComponent() {
// Logic for the dynamic component
return <div>Dynamic Content</div>;
}
Code language: JavaScript (javascript)
DynamicComponent
will be loaded dynamically, while the rest of the page (<h1>Static Title</h1>
) will be statically prerendered. This approach combines the advantages of static page generation with the flexibility of dynamic rendering, improving performance and the user experience.
Improvements to Metadata: Optimizing User Experience
Next.js 14 has introduced significant improvements in metadata management. This version separates blocking metadata from non-blocking metadata, ensuring that the initial page view is not slowed down by non-essential metadata. Optimized metadata management is crucial for a smooth user experience, avoiding issues such as page flickering or changes in element layout due to viewport or theme variations.
Before your page’s content can be transmitted by the server, some crucial metadata related to the viewport, color scheme, and theme needs to be sent to the browser first. Ensuring that these meta tags are sent with the initial page content helps ensure a smooth user experience, preventing flickering due to theme color changes or layout shifts due to viewport changes.
In Next.js 14, there is now a separation between blocking and non-blocking metadata. Only a small subset of metadata options is blocking, ensuring that non-blocking metadata does not prevent a partially prerendered page from serving the static shell.
The following metadata options are now deprecated and will be removed from metadata in a future major version:
viewport
: Sets the initial zoom and other viewport properties.colorScheme
: Sets supported modes (light/dark) for the viewport.themeColor
: Sets the color of the border around the viewport.
Starting from Next.js 14, there are new viewport
and generateViewport
options to replace these options. All other metadata options remain unchanged. You can start adopting these new APIs today, and the existing metadata options will continue to work.
Recommended video: Are we React-ing wrongly?
Next.js Learning Course: Updated Training and Resources
Recognizing the importance of education for developers, Next.js 14 comes with a new free learning course (Next.js Learn). This course covers a wide range of topics, from the Next.js App Router to authentication, integration with Postgres databases, static and dynamic rendering, to partial prerendering. The course is designed to help developers understand and fully leverage the capabilities of the framework.
Integration with Strapi and Vercel’s AI
The integration with Strapi, a headless CMS, is another notable aspect of Next.js 14. This collaboration allows you to build projects that leverage the features of both systems, offering functionalities such as full CRUD, authentication, registration, and middleware for protected paths. Additionally, Vercel has introduced a new SDK for AI, promoting the integration of artificial intelligence with web development and expanding possibilities for creating dynamic and personalized content.
Next.js and Artificial Intelligence
The integration of artificial intelligence into Next.js opens new frontiers in web development. With Vercel’s AI SDK, developers can leverage language models to create personalized user experiences and dynamic content. This integration is particularly interesting for applications that require a high degree of interactivity and customization, such as e-learning platforms, virtual assistants, and recommendation systems.
Other Changes
Here is a series of other changes related to Next.js 14:
- Change: The minimum Node.js version is now 18.17.
- Change: Removed WASM target for the next-swc build (PR).
- Change: Deprecated support for @next/font in favor of next/font (Codemod).
- Change: Modified the import of ImageResponse from next/server to next/og (Codemod).
- Change: The
next export
command is deprecated in favor ofoutput: 'export'
. - Deprecation:
onLoadingComplete
for next/image is deprecated in favor ofonLoad
. - Deprecation:
domains
for next/image is deprecated in favor ofremotePatterns
. - Feature: You can enable more detailed logging around the fetch cache (Documentation).
- Improvement: Reduced function size by 80% for a basic create-next-app application.
- Improvement: Improved memory handling when using the edge runtime in development.
Conclusion
Next.js 14 represents a significant step forward for the framework. Focusing on improving existing features rather than adding new ones, this version offers developers a sleeker, more efficient, and powerful experience. With Turbopack, Server Actions, Partial Prerendering, and integration with Strapi and artificial intelligence, Next.js 14 stands out as an ideal solution for developing modern and high-performance web applications. Developers now have an even more robust and versatile tool for creating innovative and effective web experiences.