문서
App Router 사용하기
배포

배포

축하합니다. 이제 운영 환경에 배포할 시간입니다.

Vercel을 통한 관리형 Next.js로 배포하거나, Node.js 서버, Docker 이미지, 또는 정적 HTML 파일로 자체 호스팅할 수 있습니다. next start를 사용하여 배포할 때는 모든 Next.js 기능이 지원됩니다.

운영 환경 빌드

next build를 실행하면 운영 환경용으로 최적화된 애플리케이션 버전이 생성됩니다. 페이지를 기반으로 HTML, CSS, JavaScript 파일이 생성됩니다. JavaScript는 Next.js 컴파일러를 사용하여 컴파일되고 브라우저 번들은 최소화되어 최상의 성능을 달성하고 모든 최신 브라우저를 지원합니다.

Next.js는 관리형 및 자체 호스팅 Next.js에서 사용되는 표준 배포 출력을 생성합니다. 이는 두 배포 방식 모두에서 모든 기능이 지원되도록 보장합니다. 다음 주요 버전에서는 이 출력을 Build Output API 명세로 변환할 예정입니다.

Vercel을 통한 관리형 Next.js

Next.js의 제작자이자 관리자인 Vercel은 Next.js 애플리케이션을 위한 관리형 인프라와 개발자 경험 플랫폼을 제공합니다.

Vercel에 배포하는 것은 설정이 필요 없으며 전 세계적으로 확장성, 가용성, 성능을 위한 추가 개선 사항을 제공합니다. 그러나 자체 호스팅 시에도 모든 Next.js 기능이 여전히 지원됩니다.

Vercel의 Next.js에 대해 자세히 알아보거나 무료로 템플릿을 배포하여 시도해 보세요.

자체 호스팅

Next.js를 세 가지 다른 방식으로 자체 호스팅할 수 있습니다:

Node.js 서버

Next.js는 Node.js를 지원하는 모든 호스팅 제공업체에 배포할 수 있습니다. package.json"build""start" 스크립트가 있는지 확인하세요:

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

그런 다음 npm run build를 실행하여 애플리케이션을 빌드합니다. 마지막으로 npm run start를 실행하여 Node.js 서버를 시작합니다. 이 서버는 모든 Next.js 기능을 지원합니다.

Docker 이미지

Next.js는 Docker 컨테이너를 지원하는 모든 호스팅 제공업체에 배포할 수 있습니다. Kubernetes와 같은 컨테이너 오케스트레이터에 배포하거나 모든 클라우드 제공업체에서 컨테이너 내에서 실행할 때 이 접근 방식을 사용할 수 있습니다.

  1. 기기에 Docker 설치
  2. 예제 클론 (또는 다중 환경 예제)
  3. 컨테이너 빌드: docker build -t nextjs-docker .
  4. 컨테이너 실행: docker run -p 3000:3000 nextjs-docker

Docker를 통한 Next.js는 모든 Next.js 기능을 지원합니다.

정적 HTML 내보내기

Next.js를 사용하면 정적 사이트나 단일 페이지 애플리케이션(SPA)으로 시작한 다음, 나중에 선택적으로 서버가 필요한 기능을 사용하도록 업그레이드할 수 있습니다.

Next.js는 이 정적 내보내기를 지원하므로 HTML/CSS/JS 정적 자산을 제공할 수 있는 모든 웹 서버에 배포하고 호스팅할 수 있습니다. 여기에는 AWS S3, Nginx 또는 Apache와 같은 도구가 포함됩니다.

정적 내보내기로 실행하면 서버가 필요한 Next.js 기능을 지원하지 않습니다. 자세히 알아보기.

알아두면 좋은 점:

기능

이미지 최적화

next/image를 통한 이미지 최적화next start를 사용하여 배포할 때 추가 설정 없이 자체 호스팅에서 작동합니다. 이미지를 최적화하는 별도의 서비스를 선호한다면 이미지 로더를 구성할 수 있습니다.

이미지 최적화는 next.config.js에서 사용자 정의 이미지 로더를 정의하여 정적 내보내기와 함께 사용할 수 있습니다. 이미지는 빌드 중이 아닌 런타임에 최적화됩니다.

알아두면 좋은 점:

  • glibc 기반 Linux 시스템에서 이미지 최적화는 과도한 메모리 사용을 방지하기 위해 추가 구성이 필요할 수 있습니다.
  • 최적화된 이미지의 캐싱 동작과 TTL을 구성하는 방법에 대해 자세히 알아보세요.
  • 원한다면 이미지 최적화를 비활성화하고도 next/image 사용의 다른 이점을 유지할 수 있습니다. 예를 들어, 이미지를 별도로 직접 최적화하는 경우에 유용합니다.

미들웨어

미들웨어next start를 사용하여 배포할 때 추가 설정 없이 자체 호스팅에서 작동합니다. 들어오는 요청에 접근해야 하므로 정적 내보내기를 사용할 때는 지원되지 않습니다.

미들웨어는 애플리케이션의 모든 라우트나 자산 앞에서 실행될 수 있으므로 낮은 지연 시간을 보장하기 위해 사용 가능한 모든 Node.js API의 하위 집합인 런타임을 사용합니다. 이 런타임은 "엣지에서" 실행될 필요가 없으며 단일 지역 서버에서 작동합니다. 미들웨어를 여러 지역에서 실행하려면 추가 구성과 인프라가 필요합니다.

모든 Node.js API가 필요한 로직을 추가하거나 외부 패키지를 사용하려는 경우, 이 로직을 서버 컴포넌트로서 레이아웃으로 옮길 수 있습니다. 예를 들어, 헤더 확인 및 리다이렉트가 있습니다. 또한 next.config.js를 통해 헤더, 쿠키 또는 쿼리 매개변수를 사용하여 리다이렉트 또는 리라이트할 수 있습니다. 그래도 작동하지 않는다면 사용자 정의 서버를 사용할 수도 있습니다.

환경 변수

Next.js는 빌드 시간과 런타임 환경 변수를 모두 지원할 수 있습니다.

기본적으로 환경 변수는 서버에서만 사용할 수 있습니다. 환경 변수를 브라우저에 노출하려면 NEXT_PUBLIC_ 접두사를 붙여야 합니다. 그러나 이러한 공개 환경 변수는 next build 중에 JavaScript 번들에 인라인으로 포함됩니다.

런타임 환경 변수를 읽기 위해서는 getServerSideProps를 사용하거나 App Router를 점진적으로 채택하는 것을 권장합니다. App Router를 사용하면 동적 렌더링 중에 서버에서 안전하게 환경 변수를 읽을 수 있습니다. 이를 통해 다양한 환경에서 서로 다른 값을 가진 단일 Docker 이미지를 사용할 수 있습니다.

import { unstable_noStore as noStore } from 'next/cache';
 
export default function Component() {
  noStore();
  // cookies(), headers() 및 기타 동적 함수도
  // 동적 렌더링을 선택하여
  // 이 환경 변수가 런타임에 평가되도록 합니다
  const value = process.env.MY_VALUE
  ...
}

알아두면 좋은 점:

  • register 함수를 사용하여 서버 시작 시 코드를 실행할 수 있습니다.
  • runtimeConfig 옵션은 권장하지 않습니다. 이는 독립 실행형 출력 모드에서 작동하지 않습니다. 대신 App Router를 점진적으로 채택하는 것을 권장합니다.

캐싱 및 ISR

Next.js는 응답, 생성된 정적 페이지, 빌드 출력, 그리고 이미지, 폰트, 스크립트와 같은 기타 정적 자산을 캐시할 수 있습니다.

캐싱 및 페이지 재검증(증분 정적 재생성(ISR) 또는 App Router의 새로운 함수 사용)은 동일한 공유 캐시를 사용합니다. 기본적으로 이 캐시는 Next.js 서버의 파일 시스템(디스크)에 저장됩니다. 이는 Pages와 App Router를 모두 사용하여 자체 호스팅할 때 자동으로 작동합니다.

캐시된 페이지와 데이터를 지속적인 스토리지에 유지하거나 Next.js 애플리케이션의 여러 컨테이너 또는 인스턴스 간에 캐시를 공유하려는 경우 Next.js 캐시 위치를 구성할 수 있습니다.

자동 캐싱

  • Next.js는 완전히 불변인 자산에 대해 Cache-Control 헤더를 public, max-age=31536000, immutable로 설정합니다. 이는 재정의할 수 없습니다. 이러한 불변 파일에는 파일 이름에 SHA 해시가 포함되어 있어 안전하게 무기한 캐시될 수 있습니다. 예를 들어, 정적 이미지 가져오기가 있습니다. 이미지의 TTL을 구성할 수 있습니다.
  • 증분 정적 재생성(ISR)은 Cache-Control 헤더를 s-maxage: <revalidate in getStaticProps>, stale-while-revalidate로 설정합니다. 이 재검증 시간은 getStaticProps 함수에서 초 단위로 정의됩니다. revalidate: false를 설정하면 기본적으로 1년의 캐시 기간이 적용됩니다.
  • 동적으로 렌더링되는 페이지는 사용자별 데이터가 캐시되는 것을 방지하기 위해 Cache-Control 헤더를 private, no-cache, no-store, max-age=0, must-revalidate로 설정합니다. 이는 App Router와 Pages Router 모두에 적용됩니다. 여기에는 초안 모드도 포함됩니다.

정적 자산

정적 자산을 다른 도메인이나 CDN에서 호스팅하려면 next.config.js에서 assetPrefix 구성을 사용할 수 있습니다. Next.js는 JavaScript 또는 CSS 파일을 검색할 때 이 자산 접두사를 사용합니다. 자산을 다른 도메인으로 분리하면 DNS 및 TLS 해결에 추가 시간이 소요되는 단점이 있습니다.

assetPrefix에 대해 자세히 알아보기.

캐싱 구성

기본적으로 생성된 캐시 자산은 메모리(기본 50mb)와 디스크에 저장됩니다. Kubernetes와 같은 컨테이너 오케스트레이션 플랫폼을 사용하여 Next.js를 호스팅하는 경우, 각 파드는 캐시의 복사본을 가지게 됩니다. 기본적으로 파드 간에 캐시가 공유되지 않으므로 오래된 데이터가 표시되는 것을 방지하기 위해 Next.js 캐시를 구성하여 캐시 핸들러를 제공하고 메모리 내 캐싱을 비활성화할 수 있습니다.

자체 호스팅 시 ISR/데이터 캐시 위치를 구성하려면 next.config.js 파일에서 사용자 정의 핸들러를 구성할 수 있습니다:

next.config.js
module.exports = {
  cacheHandler: require.resolve("./cache-handler.js"),
  cacheMaxMemorySize: 0, // 기본 메모리 내 캐싱 비활성화
};

그런 다음 프로젝트의 루트에 cache-handler.js를 생성합니다. 예를 들어:

cache-handler.js
const cache = new Map();
 
module.exports = class CacheHandler {
  constructor(options) {
    this.options = options;
  }
 
  async get(key) {
    // 이는 지속적인 스토리지와 같은 어디에나 저장될 수 있습니다
    return cache.get(key);
  }
 
  async set(key, data, ctx) {
    // 이는 지속적인 스토리지와 같은 어디에나 저장될 수 있습니다
    cache.set(key, {
      value: data,
      lastModified: Date.now(),
      tags: ctx.tags,
    });
  }
 
  async revalidateTag(tag) {
    // 캐시의 모든 엔트리를 반복합니다
    for (let [key, value] of cache) {
      // 값의 태그가 지정된 태그를 포함하면 이 엔트리를 삭제합니다
      if (value.tags.includes(tag)) {
        cache.delete(key);
      }
    }
  }
};

사용자 정의 캐시 핸들러를 사용하면 Next.js 애플리케이션을 호스팅하는 모든 파드 간의 일관성을 보장할 수 있습니다. 예를 들어, Redis나 AWS S3와 같은 어디에나 캐시된 값을 저장할 수 있습니다.

알아두면 좋은 점:

  • revalidatePath는 캐시 태그 위에 있는 편의 레이어입니다. revalidatePath를 호출하면 제공된 페이지에 대한 특별한 기본 태그로 revalidateTag 함수를 호출합니다.

빌드 캐시

Next.js는 next build 중에 제공되는 애플리케이션 버전을 식별하기 위한 ID를 생성합니다. 동일한 빌드를 사용하여 여러 컨테이너를 부팅해야 합니다.

환경의 각 단계에 대해 다시 빌드하는 경우, 컨테이너 간에 사용할 일관된 빌드 ID를 생성해야 합니다. next.config.js에서 generateBuildId 명령을 사용하세요:

next.config.js
module.exports = {
  generateBuildId: async () => {
    // 이는 최신 git 해시를 사용하는 등 무엇이든 될 수 있습니다
    return process.env.GIT_HASH;
  },
};

버전 불일치

Next.js는 대부분의 버전 불일치 인스턴스를 자동으로 완화하고 감지되면 애플리케이션을 자동으로 다시 로드하여 새 자산을 검색합니다. 예를 들어, deploymentId가 일치하지 않는 경우, 페이지 간 전환은 프리페치된 값을 사용하는 대신 하드 네비게이션을 수행합니다.

애플리케이션이 다시 로드될 때, 페이지 네비게이션 간에 지속되도록 설계되지 않은 경우 애플리케이션 상태가 손실될 수 있습니다. 예를 들어, URL 상태나 로컬 스토리지를 사용하면 페이지 새로 고침 후에도 상태가 유지됩니다. 그러나 useState와 같은 컴포넌트 상태는 이러한 네비게이션에서 손실됩니다.

Vercel은 Next.js 애플리케이션을 위한 추가 버전 불일치 보호를 제공하여 새 버전이 배포된 후에도 이전 버전의 자산과 함수를 이전 클라이언트에서 계속 사용할 수 있도록 합니다.

next.config.js 파일에서 deploymentId 속성을 수동으로 구성하여 각 요청이 ?dpl 쿼리 문자열이나 x-deployment-id 헤더를 사용하도록 할 수 있습니다.

스트리밍 및 Suspense

Next.js App Router는 자체 호스팅 시 스트리밍 응답을 지원합니다. Nginx나 유사한 프록시를 사용하는 경우 스트리밍을 활성화하기 위해 버퍼링을 비활성화하도록 구성해야 합니다.

예를 들어, Nginx에서 X-Accel-Bufferingno로 설정하여 버퍼링을 비활성화할 수 있습니다:

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: "/:path*{/}?",
        headers: [
          {
            key: "X-Accel-Buffering",
            value: "no",
          },
        ],
      },
    ];
  },
};

부분 프리렌더링

부분 프리렌더링 (실험적)은 Next.js와 함께 기본적으로 작동하며 CDN 기능이 아닙니다. 여기에는 Node.js 서버로의 배포(next start를 통해) 및 Docker 컨테이너와 함께 사용될 때가 포함됩니다.

CDN과 함께 사용

Next.js 애플리케이션 앞에 CDN을 사용할 때, 동적 API에 접근하면 페이지에 Cache-Control: private 응답 헤더가 포함됩니다. 이는 결과 HTML 페이지가 캐시할 수 없음을 표시하기 위한 것입니다. 페이지가 완전히 정적으로 프리렌더링된 경우, 페이지가 CDN에서 캐시될 수 있도록 Cache-Control: public을 포함합니다.

정적 및 동적 컴포넌트의 혼합이 필요하지 않은 경우, 전체 라우트를 정적으로 만들고 출력 HTML을 CDN에 캐시할 수 있습니다. 이 자동 정적 최적화는 동적 API가 사용되지 않을 때 next build를 실행할 때의 기본 동작입니다.