Next.js
lastmod 2025-12-07created 2021-06-1171 edits
Next.js is an open-source web development framework built on top of Node.js that enables React-based web application features such as server-side rendering and static web page generation. The React documentation mentions Next.js as one of its "recommended toolchains" and advises it as one solution for developers building server-rendered websites with Node.js.
The copyright and trademarks of Next.js are owned by Vercel, which also maintains and leads its open-source development.
Background
Next.js is a React (JavaScript library) framework that supports several additional features, including server-side rendering and static website generation. React is a JavaScript library traditionally used to build web applications rendered in the client's browser with JavaScript. However, developers recognize several problems with this strategy, such as failing to serve users who cannot access JavaScript or have disabled it, potential security issues, significantly longer page load times, and harm to the site's overall search engine optimization. Frameworks like Next.js work around these problems by allowing part or all of a website to be rendered on the server side before it is sent to the client. Next.js is one of the most popular frameworks for React. It is one of several recommended "toolchains" you can use when starting a new app, all of which provide a layer of abstraction that supports common tasks. Next.js requires Node.js and can be initialized with the Node package manager.
In 2019, Google contributed to the Next.js project, including 43 pull requests. As of March 2022, the framework is used by many large websites, including Walmart, Apple, Nike, Netflix, TikTok, Uber, Lyft, and Starbucks. In early 2020, Vercel secured $21 million in Series A funding to support improvements to the software. Guillermo Rauch, the framework's original author, is currently the CEO of Vercel, and the project's lead maintainer is Tim Neutkens.
Categories
- React
- ReactDOM
- next.config.js
- NextJS:ProjectStructure - Project folder structure
Routing
- NextJS:PagesAndLayouts
- NextJS:DynamicRoutes
- NextJS:ParallelRoutes - Parallel routing. Folders starting with
@. - NextJS:LinkingAndNavigating
- NextJS:RouteGroups
- NextJS:CustomApp - Explanation of the
pages/_app.jsfile. - NextJS:CustomDocument
- NextJS:CustomErrors
- NextJS:APIRoutes
- NextJS:Internationalization
- NextJS:Authenticating
- NextJS:RouteHandlers - How to implement GET, POST, and other APIs on the Server Side
- NextJS:Middleware
- NextJS:ProjectOrganization - Project folder structure, etc.
- NextJS:Internationalization - Related to i18n
Data Fetching
- NextJS:Fetching
- NextJS:Caching
- NextJS:Revalidating
- NextJS:Patterns
- NextJS:ServerActions
NextJS:Rendering
- NextJS:SSR - Server-side Rendering (SSR)
- NextJS:SSG - Static Site Generation (SSG)
- NextJS:ISR - Incremental Static Regeneration (ISR)
- NextJS:ASO - Automatic Static Optimization
- NextJS:CSR - Client-side Rendering (CSR)
- NextJS:Edge - Edge and Node.js Runtimes
Data Fetching
- NextJS:getStaticProps
- NextJS:getStaticPaths
- NextJS:getServerSideProps
- NextJS:IncrementalStaticRegeneration
- NextJS:ClientSideFetching
- NextJS:BuildingForms
Styling
- NextJS:CSSModules
- NextJS:TailwindCSS
- NextJS:CSS-in-JS
- NextJS:Sass
Optimizing
- NextJS:Images
- NextJS:Fonts
- NextJS:Scripts
- NextJS:StaticAssets
- NextJS:LazyLoading
- NextJS:Analytics
- NextJS:OpenTelemetry
- NextJS:Instrumentation
- NextJS:Testing
- NextJS:Configuring
File Conventions
- NextJS:default.js
- NextJS:error.js
- NextJS:layout.js
- NextJS:loading.js
- NextJS:not-found.js
- NextJS:page.js
- NextJS:route.js
- NextJS:RouteSegmentConfig
- NextJS:template.js
- NextJS:MetadataFiles
- NextJS:Icons - favicon, icon, and apple-icon
- NextJS:opengraph-image
- NextJS:twitter-image
- NextJS:robots.txt
- NextJS:sitemap.xml
with Supabase
ETC
- node-fetch
- NextAuth.js
- react-query (TanStack Query)
- SWR (stale-while-revalidate)
Functions
- NextJS:Functions:getServersideProps
- NextJS:Functions:getStaticPaths
- NextJS:Functions:getStaticProps
- NextJS:Functions:generateStaticParams
- NextJS:Functions:notFound
- NextJS:Functions:redirect
- NextJS:Functions:revalidatePath
- NextJS:Functions:revalidateTag
- NextJS:Functions:useRouter
Boilerplate
- Next.js Enterprise Boilerplate
- https://github.com/Blazity/next-enterprise
- High-performance, easy-to-maintain enterprise-grade Next.js template
- High-performance, easy-to-maintain enterprise-grade Next.js template
- Tailwind CSS + ESlint + Prettier + Jest + Playwright + Storybook
- Supports Observability / Health Check / Commit Git Hook / GitHub Actions
- Automated code review based on ChatGPT
- Perfect Lighthouse score
Terms
- Hydrate
- What is Hydrate in Next.js? :: Inyong's World
- Hydrate is the process of sending a static page rendered on the Server Side and the bundled JS files to the client, then matching the HTML code with the React JS code on the client side.
How to start
TypeScript app
npx create-next-app@latest --ts
# or
yarn create next-app --typescript
# or
pnpm create next-app --ts
Environment variables
env files use the following conventions.
-
.env.local(for local development) -
.env.development -
.env.production(for server deployment) -
.env.test
Environment variables are exposed in the browser only if you use REACT_APP_ for React or NEXT_PUBLIC_ for Nextjs. Otherwise they are exposed only in the Node.js environment.
However, dynamic lookups are not inlined.
// This will NOT be inlined, because it uses a variable
const varName = 'NEXT_PUBLIC_ANALYTICS_ID'
setupAnalyticsService(process.env[varName])
// This will NOT be inlined, because it uses a variable
const env = process.env
setupAnalyticsService(env.NEXT_PUBLIC_ANALYTICS_ID)
Private Gitlab integration in CDK Amplify
How to host AWS Amplify from a private Gitlab repository using AWS CDK.
If you use the GitLabSourceCodeProvider class defined in CDK, Amplify reads the repository on GitLab and fetches the source. There is an example, and owner, repository, and oauthToken are required inputs.
/**
* #### GitLabSourceCodeProvider Example (CDK v2 / typescript) ####
*/
const amplifyApp = new amplify.App(this, "MyApp", {
sourceCodeProvider: new amplify.GitLabSourceCodeProvider({
owner: "<user>",
repository: "<repo>",
oauthToken: SecretValue.secretsManager("my-gitlab-token"),
}),
});
When entering owner, if the project belongs to a Gitlab group, you must enter the group name. For example, if it is gitlab.com/mygroup/저장소네임, you must enter mygroup, but I spent a long time testing while entering only allssu or entering the numeric user ID and changing only repository. Entering a username or ID as owner just gives a 404 error saying the project cannot be found. If the project is under a user, entering the username works, but if it is under a group, owner must be the group name. I wandered around for a long time because of this, and the CDK documentation, perhaps because it is an external service, did not explain it as kindly as I expected. 😭
For repository, just write the repository name as is.
Finally, it shows an example of using Secrets Manager to enter oauthToken; if you create the Secrets Manager in CDK, you can integrate it cleanly.
Creating a Gitlab access token and Secrets Manager
The stack code that provisions Secrets Manager through CDK, without entering the secret value, is as follows:
/**
* #### Secrets Manager Stack (CDK v2 / typescript) ####
*
* /lib/secretsmanager-stack.ts
*/
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import { aws_secretsmanager as secretsmanager } from "aws-cdk-lib";
export class SecretsmanagerStack extends cdk.Stack {
public readonly secret: secretsmanager.Secret; // 다른 스택으로 Secret을 전달시키기 위한 클래스 속성
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
this.secret = new secretsmanager.Secret(this, "Secret", {});
}
}
When you deploy through CDK, the secret value is generated as a random value, so I went into the AWS Management Console directly and changed it to the Gitlab Personal Access Token. The secret is not included in the CDK source and is managed more securely.
Integrating Secrets Manager in the Amplify stack
So that Amplify can receive the secret, create an interface that extends StackProps. This lets you integrate without exposing even the secret name (identifier) that holds the secret value.
/**
* #### Amplify Stack (CDK v2 / typescript) ####
*
* /lib/amplify-stack.ts
*/
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as amplify from "@aws-cdk/aws-amplify-alpha";
import { SecretValue } from "aws-cdk-lib";
interface StackProps extends cdk.StackProps {
secret: cdk.aws_secretsmanager.Secret;
}
export class AmplifyStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
new amplify.App(this, "amplify", {
appName: "MyApp",
sourceCodeProvider: new amplify.GitLabSourceCodeProvider({
owner: "group", // 프로젝트가 깃랩 그룹에 포함되어있다면, 그룹 이름을 적어야 한다.
repository: "app",
oauthToken: SecretValue.secretsManager(props.secret.secretName), // 전달받은 Secret Name
}),
});
}
}
The Secrets Manager stack and the Amplify stack can now pass values to each other, and the Secret was passed to the Amplify stack in /bin, the entry point of CDK.
/**
* #### 스택 연결 및 생성 (CDK v2 / typescript) ####
*
* /bin/cdk.ts
*/
#!/usr/bin/env node
import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import { CognitoStack } from "../lib/cognito-stack";
import { AmplifyStack } from "../lib/amplify-stack";
import { SecretsmanagerStack } from "../lib/secretsmanager-stack";
const app = new cdk.App();
const { secret } = new SecretsmanagerStack(app, "SecretsmanagerStack", {
description: "Amplify Secrets",
});
new AmplifyStack(app, "AmplifyStack", {
secret,
description: "Next.js 13 App Amplify",
});
Reading the header list on the server side
You can read the full list of headers as follows.
import {headers} from 'next/headers';
function getHeadersRecord() {
const result = {} as Record<string, string>;
const headersList = headers();
headersList.forEach((value, key) => {
result[key] = value;
});
return result;
}
Sample
The result looks roughly like this.
header[host]=localhost:3000
header[user-agent]=Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0
header[accept]=*/*
header[accept-language]=en-US,en;q=0.5
header[accept-encoding]=gzip, deflate, br
header[referer]=http://localhost:3000/settings/profile
header[next-url]=/en/settings/profile
header[dnt]=1
header[connection]=keep-alive
header[cookie]=isNonPlugin=1; proj_lng=ko; proj-lng=en;
header[sec-fetch-dest]=empty
header[sec-fetch-mode]=cors
header[sec-fetch-site]=same-origin
header[x-forwarded-host]=localhost:3000
header[x-forwarded-port]=3000
header[x-forwarded-proto]=http
header[x-forwarded-for]=::ffff:127.0.0.1
Troubleshooting
window is not defined error
- [Official] Advanced Features: Dynamic Import | Next.js
- (react) window is not defined error (apexchart)
This error occurs because the call happened on the server side.
When nextjs, which supports SSR, is refreshed, it imports that part, but there is no window object in ssr, so you get "not defined".
nextjs provides a function to solve this: the function called dynamic.
Import it as follows.
import dynamic from 'next/dynamic'
const ApexChart = dynamic(() => import("react-apexcharts"), { ssr: false });
The Middleware "pages/middleware" must export a middleware or a default function
Name the middleware function in the root middleware.ts "middleware", or use export default.
Largest Contentful Paint (LCP)
warn-once.js:16 Image with src "/_next/static/media/proj.run.aac09183.svg" was detected as the Largest Contentful Paint (LCP). Please add the "priority" property if this image is above the fold.
Read more: https://nextjs.org/docs/api-reference/next/image#priority
Image with src "/_next/static/media/..." has either width or height modified, but not the other
warn-once.js:16 Image with src "/_next/static/media/proj.run.aac09183.svg" has either width or height modified, but not the other. If you use CSS to change the size of your image, also include the styles 'width: "auto"' or 'height: "auto"' to maintain the aspect ratio.
Prevent client components from being async functions
./app/[lng]/page.tsx
8:1 Warning: Prevent client components from being async functions. See: https://nextjs.org/docs/messages/no-async-client-component @next/next/no-async-client-component
Per the React Server Component RFC on Promise support, client components cannot be async functions.
Possible Ways to Fix It:
- Remove the
asynckeyword from the client component function declaration, or - Convert the client component to a server component
Error: No response is returned from route handler
⨯ Error: No response is returned from route handler '/home/your/Project/web/app/api/auth/login/route.ts'. Ensure you return a `Response` or a `NextResponse` in all branches of your handler.
Consider adding an error boundary to your tree to customize error handling behavior
See also
- node
- Rakkas - Web framework alternative to Next.js
- OpenNext
- Nextron (Next.js + Electron)
- CapRover - Free and Open Source PaaS!
- Open Graph Protocol (OGP)
- next-yak - Rust-based zero-runtime CSS-in-JS for Next.js
- CVE-2025-55182 (React2Shell)
Favorite site
- serverless-next.js deploy - How to deploy a web application built with Next JS.
- Serving Next.js bundle files efficiently with CloudFront + CloudFront functions!
- What you should know before choosing Next.js | GeekNews
Tutorials
- Getting Started: Installation | Next.js
- (Next.js) Getting started - Let's learn how to create and run a React project with Next.js.
- [Recommended] NextJS official documentation summary (based on version 12)
- (NextJS) Basics summary
-
Next.js 13 lecture marathon (lectures 1–6) - YouTube - Codingapple- Too basic. - [Recommended] Next.js 13: complete guide to Server Components and the App Directory
- [Recommended] Learning the basic concepts of next.js | Record rather than remember - Seems to be an old version
Guide
- Migrating the open-source BBC React SPA to Next.js and Vercel | GeekNews - (Next.js, Vercel)
- [Original] Migrating a large, open-source React application to Next.js and Vercel – Vercel
- HMR: 1.3s to 131ms (10x faster)
- Network requests: 57 to 34 (🔻40%)
- 20,000 LOC removed and 30 fewer deps (🤯)
with Cloud Deploy
Templates
- saas-starter-ko: Next.js (15) templ for building SaaS web services | GeekNews
- Github - kych0912/saas-starter-ko
- Get started quickly with Next.js, Postgres, Stripe, and shadcn/ui.
- Adds what was missing from nextjs/saas-starter made by vercel
- For reference, nextjs/saas-starter is a template that implements simple features needed for SaaS, such as basic login, Stripe payments, and a dashboard.
- 304 Not Modified
- Calendso
- Clip-JS
- Cloud Computing
- Cookie
- CVE-2025-55182
- Electron
- HTML:button
- I18next
- I18next-browser-languagedetector
- Internationalization and localization
- Jamstack
- JavaScript:Libraries
- KickstartDS
- Next-i18next
- Next-yak
- Next.config.js
- NextI18next:ClientSideUseTranslation
- NextJS:CustomApp
- NextJS:Functions
- NextJS:Functions:generateStaticParams
- NextJS:Functions:getServersideProps
- NextJS:Functions:getStaticPaths
- NextJS:Functions:getStaticProps
- NextJS:Functions:redirect
- NextJS:Images
- NextJS:Internationalization
- NextJS:Middleware
- NextJS:ParallelRoutes
- NextJS:ProjectOrganization
- NextJS:ProjectStructure
- NextJS:Rendering
- NextJS:RouteGroups
- NextJS:RouteHandlers
- NextJS:ServerActions
- Nextron
- Node-fetch
- Nue
- Optio
- Platform as a Service
- Rakkas
- React
- React-cookie
- React-hot-toast
- React-i18next
- React:Context
- Remix
- Shadcn UI
- Socket.io
- Supabase
- Supabase:Auth
- Tachyon
- Vercel
- WebContainers
- Webpack