Guides: ISR
Learn how to create or update static pages at runtime with Incremental Static Regeneration.

Next.js 블로그, MDX 대신 Notion API로 재구축하기
MDX로 관리하던 블로그를 Notion API를 이용한 글작성 경험 개선기
왜 ISR이 제대로 이루어지지 않지?



react-notion-x
const notionX = new NotionAPI(); ... export const getPostRecordMap = async (pageId: string) => { const recordMap = await notionX.getPage(pageId); return recordMap; };
export class NotionAPI { public async getPage(pageId: string): Promise<notion.ExtendedRecordMap> { const page = await this.getPageRaw(pageId) ... } public async getPageRaw(pageId: string) { ... return this.fetch<notion.PageChunk>({ endpoint: 'loadPageChunk', body, kyOptions }) } public async fetch<T>(...) { ... const res = await ky.post(url, { mode: 'no-cors', ...this._kyOptions, ...kyOptions, json: body, headers }) return ret.json(); } }
npmnpm: ky
npm: ky
Tiny and elegant HTTP client based on the Fetch API. Latest version: 1.10.0, last published: 7 days ago. Start using ky in your project by running `npm i ky`. There are 937 other projects in the npm registry using ky.
public async fetch<T>(...) { ... const res = await ky.post(url, { mode: 'no-cors', ...this._kyOptions, ...kyOptions, json: body, headers }) return ret.json(); }

Request: mode property - Web APIs | MDN
The mode read-only property of the Request interface contains the mode of the request (e.g., cors, no-cors, same-origin, or navigate.) This is used to determine if cross-origin requests lead to valid responses, and which properties of the response are readable.
어떻게 해결할 수 있나?
const notionX = new NotionAPI({ kyOptions: { mode: "cors", }, });
서버 간 통신에서 정말 ‘no-cors’가 무시되나?
import express from "express"; const app = express(); const port = 4000; app.post("/test-cors", (req, res) => { console.log("✅ /test-cors endpoint received a request."); // ⚠️ 중요: CORS 관련 헤더를 전혀 보내지 않음! // res.setHeader('Access-Control-Allow-Origin', '*'); // 이 코드가 없음 res.json({ message: "This is a secret message from the server!", success: true, }); }); app.listen(port, () => { console.log(`🚀 Test server listening at http://localhost:${port}`); });
import express from "express"; const app = express(); const port = 3000; app.get("/call-other-server", async (req, res) => { console.log( "🚀 클라이언트 서버(3000)에서 API 서버(4000)로 요청 보내는 중..." ); try { // 🔥 핵심: 서버에서 다른 서버로 요청 (CORS 헤더 없어도 OK!) const response = await fetch("http://localhost:4000/test-cors", { method: "POST", headers: { "Content-Type": "application/json", }, }); const data = await response.json(); console.log("✅✅✅ 서버 간 통신 성공! 받은 데이터:", data); res.json({ message: "서버 간 통신 성공!", fromOtherServer: data, proof: "CORS 헤더가 없어도 서버 간 통신은 문제없음!", }); } catch (error) { console.error("❌ 서버 간 통신 실패:", error); res.status(500).json({ error: error.message }); } }); app.listen(port, () => { console.log(`🌐 클라이언트 서버가 http://localhost:${port}에서 실행 중`); console.log(`📡 테스트: curl http://localhost:${port}/call-other-server`); });


ISR이 안되는 ‘진짜’ 이유?
if (fetchType === "ky") { response = await ky.post(url, { mode: "no-cors", headers, json: body, }); } else if (fetchType === "fetch") { response = await fetch(url, { mode: "no-cors", method: "POST", headers, body: JSON.stringify(body), }); }
=== ISR 페이지 생성 시작: fetch === 생성 시간: 2025-09-17T17:10:51.189Z 환경: Server (ISR) 🌐 Native Fetch API로 테스트 FETCH 환경: Server (ISR) -------- FETCH 요청 URL: https://www.notion.so/api/v3/loadPageChunk -------- FETCH 응답 타입: basic FETCH 응답 상태: 200 FETCH 응답 OK: true FETCH JSON 파싱 시도... FETCH JSON 파싱 성공 ✅ ISR 페이지 생성 성공: 285ms === ISR 페이지 생성 완료: fetch ===
=== ISR 페이지 생성 시작: ky === 생성 시간: 2025-09-17T15:07:54.134Z 환경: Server (ISR) KY 라이브러리로 테스트 KY 환경: Server (ISR) -------- KY 요청 URL: https://www.notion.so/api/v3/loadPageChunk -------- ❌ ISR 페이지 생성 실패 (5001ms): 5초 타임아웃: KY 요청 실패 === ISR 페이지 생성 완료: ky ===
패치 표준
이 표준의 목표는 웹 플랫폼 전반에 걸쳐 패칭을 통합하고, 이에 관련된 모든 것에 대해 일관된 처리를 제공하는 것입니다. 여기에는 다음이 포함됩니다: