Skip to content
Search

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

Routing

Data Fetching

NextJS:Rendering

Data Fetching

  • NextJS:getStaticProps
  • NextJS:getStaticPaths
  • NextJS:getServerSideProps
  • NextJS:IncrementalStaticRegeneration
  • NextJS:ClientSideFetching
  • NextJS:BuildingForms

Styling

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
  • NextJS:next-env.d.ts

with Supabase

ETC

Functions

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

npm install -g create-next-app
npx create-next-app my-app

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

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.

export async function middleware(req: NextRequest) {
  // ...
}

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 async keyword 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

Favorite site

Tutorials

Guide

with Cloud Deploy

Templates

author Zer0 sitemap