2024년 WordPress에서 Next.js로 마이그레이션하면서 금융 SaaS 회사가 $420K를 절약하다

2024년 말, Series C 금융 서비스 SaaS 회사가 실제로 돈을 잃고 있는 문제를 안고 우리를 찾아왔습니다. 마케팅 사이트, 고객 포털, 문서 허브가 모두 WordPress에서 실행되고 있었는데, 프리미엄 플러그인이 복잡하게 얽혀 있고, 연 $420K의 엔터프라이즈 CMS 라이선스 스택이 있었으며, 페이지 로드 시간이 규정 준수 팀을 불안하게 만들고 있었습니다. 그들은 단 1초의 다운타임도 없이 현대적인 헤드리스 아키텍처로 이동해야 했습니다 — 금융 서비스에서 다운타임은 규제 감시, 신뢰 손실, 그리고 매우 진지한 사람들로부터의 매우 비용이 많이 드는 전화를 의미하기 때문입니다.

이것이 우리가 이를 어떻게 해냈는지의 전체 이야기입니다.

목차

WordPress to Next.js Migration: Financial SaaS Saves $420K ARR

시작점: 압박 상태의 WordPress 모놀리식 아키텍처

상황을 설명해보겠습니다. 이 회사 — 우리가 FinEdge라고 부르겠습니다 (NDA, 이해하시겠죠) — 세 개의 고유한 웹 속성 전체에 약 12,000개의 페이지 콘텐츠를 가지고 있었습니다:

  1. 마케팅 사이트 — 제품 페이지, 랜딩 페이지, 2,400개 이상의 게시물이 있는 블로그
  2. 고객 포털 — 계정 대시보드, 온보딩 흐름, 문서 관리
  3. 문서 허브 — API 문서, 규정 준수 가이드, 통합 튜토리얼

이 세 가지 모두 WP Engine의 엔터프리아즈 계층에 호스팅된 단일 WordPress 멀티사이트 설치에서 실행되었습니다. 플러그인 상황은... 좀 그랬습니다. WPGraphQL, Advanced Custom Fields Pro, Yoast SEO Premium, WP Rocket, Gravity Forms, 그리고 콘텐츠 변경에 대한 SOC 2 규정 준수 로깅을 처리하는 이전 에이전시가 구축한 맞춤 플러그인을 포함하여 활성화된 47개의 플러그인을 실행하고 있었습니다.

실제 통증 포인트:

  • 모바일에서 평균 4.2초의 페이지 로드 시간 (Google CrUX 데이터)
  • 68%의 페이지에서 Core Web Vitals 실패 — LCP가 중앙값 5.1s로 매우 심각
  • 연 $420K의 라이선스 비용 WP Engine 엔터프라이즈 호스팅, 프리미엄 플러그인, WAF, CDN, 그리고 별도의 스테이징 환경 걸쳐
  • 피크 시간에 WordPress 관리자가 8-12초 대기 콘텐츠 편집자들이 응답하기를 기다림
  • 보안 패치 2주마다 전담 DevOps 시간이 필요 — 금융 서비스 규제 당국은 타협하지 않음
  • 미리보기 배포 없음 — 콘텐츠 팀이 스테이징으로 푸시하고 캐시 무효화를 위해 4분을 기다려야 함

엔지니어링 부사장이 발견 전화 중에 우리에게 말했습니다: "우리는 웹사이트 인프라에 두 명의 수석 엔지니어보다 더 많은 비용을 지출하고 있습니다. 그리고 여전히 느립니다."

왜 헤드리스 Next.js가 올바른 선택이었는가

아키텍처 단계에서 여러 옵션을 평가했습니다. 테이블에 있던 것들:

옵션 장점 단점 예상 연간 비용
WordPress (최적화) 팀에 친숙함, 마이그레이션 불필요 여전히 느림, 라이선스 변경 없음 $420K
Webflow Enterprise 시각적 편집, 빠른 배포 포털/앱 요구사항 제한, 공급업체 종속 $180K
Next.js + Sanity 매우 빠름, 유연함, 실시간 미리보기 마이그레이션 노력, 팀 역량 강화 $38K
Next.js + Contentful 강력한 엔터프라이즈 기능, 좋은 DX 사용자별 가격 책정이 잘못 확장됨 $95K
Astro + Storyblok 정적 콘텐츠에 좋음, 경량 동적 포털 요구사항에 덜 성숙함 $42K

우리는 Next.js 14 (App Router)와 Sanity를 헤드리스 CMS로 사용하기로 결정했습니다. 이유는:

  • FinEdge의 포털에는 Server-side rendering이 필요한 동적 인증 경로가 있었습니다. Next.js는 React Server Components로 이를 기본 제공합니다.
  • Sanity의 실시간 협력 및 GROQ 쿼리 언어는 콘텐츠 편집자에게 WordPress보다 훨씬 더 나은 경험을 제공했습니다.
  • 가격 모델 (Sanity의 Growth plan이 월 $99 + Vercel Pro)은 인프라 비용을 연 $420K에서 대략 $38K로 낮추었습니다.
  • FinEdge의 엔지니어링 팀이 이미 React를 알고 있었습니다. Next.js로의 역량 강화는 몇 개월이 아니라 며칠 단위로 측정되었습니다.

우리는 문서 허브가 대부분 정적 콘텐츠이기 때문에 Astro를 진지하게 고려했지만, 모든 것을 하나의 프레임워크로 유지하는 운영 단순성이 우선했습니다. 문서 사이트가 독립 프로젝트였다면 Astro가 최고의 선택이었을 것입니다.

마이그레이션 아키텍처

우리가 설계한 높은 수준의 아키텍처입니다:

┌─────────────────┐     ┌──────────────────┐
│   Sanity CMS     │────▶│  Next.js on       │
│   (Content)      │     │  Vercel (Edge)    │
└─────────────────┘     └──────────────────┘
         │                        │
         │                        ▼
         │               ┌──────────────────┐
         │               │  Cloudflare       │
         │               │  (DNS + WAF)      │
         │               └──────────────────┘
         │                        │
         ▼                        ▼
┌─────────────────┐     ┌──────────────────┐
│  Media Pipeline  │     │  End Users        │
│  (Cloudinary)    │     └──────────────────┘
└─────────────────┘

주요 구성요소:

콘텐츠 레이어

  • Sanity를 마케팅 콘텐츠, 블로그 게시물, 문서의 주요 CMS로 사용
  • 기존 WordPress 콘텐츠 유형에 매핑되는 맞춤 Sanity 스키마
  • Portable Text for rich content (WordPress의 Gutenberg 블록 대체)

애플리케이션 레이어

  • Next.js 14 with App Router, Vercel의 Pro plan에 배포
  • 마케팅 사이트 및 문서에 대한 React Server Components
  • 클라이언트 컴포넌트는 상호작용이 진정으로 필요한 경우에만 (양식, 대시보드, 대화형 차트)
  • 기존 Auth0 설정과 통합된 포털 경로에 대한 인증을 위한 미들웨어

인프라 레이어

  • Vercel for hosting and edge functions
  • Cloudflare for DNS management and additional WAF rules (financial services compliance requirement)
  • Cloudinary for image optimization and transformation — replaced 3 WordPress image plugins

WordPress to Next.js Migration: Financial SaaS Saves $420K ARR - architecture

무중단 전략: 병렬 실행

이것이 제가 밤잠을 설쳤던 부분입니다. FinEdge는 몇 분의 다운타임도 감당할 수 없었습니다. 그들의 고객 포털은 금융 거래를 처리하고, 어떤 중단이든 규제 당국에 강제 사건 보고를 트리거합니다.

우리가 이를 어떻게 했는지:

Phase 1: 콘텐츠 동기화 (주 1-3)

우리는 마이그레이션 기간 동안 지속적으로 실행되는 맞춤 WordPress-to-Sanity 동기화 파이프라인을 구축했습니다:

// WP-to-Sanity 동기화 워커의 단순화된 버전
import { createClient } from '@sanity/client'
import WPGraphQL from './wp-graphql-client'

const sanity = createClient({
  projectId: process.env.SANITY_PROJECT_ID,
  dataset: 'production',
  token: process.env.SANITY_WRITE_TOKEN,
  apiVersion: '2024-10-01',
  useCdn: false,
})

async function syncPosts(since: string) {
  const posts = await WPGraphQL.getModifiedPosts(since)
  
  const transaction = sanity.transaction()
  
  for (const post of posts) {
    const sanityDoc = transformWPToSanity(post)
    transaction.createOrReplace(sanityDoc)
  }
  
  await transaction.commit()
  console.log(`Synced ${posts.length} posts`)
}

// 크론을 통해 5분마다 실행됨

이는 마이그레이션 전체 중에 콘텐츠 편집자가 WordPress에서 계속 작업할 수 있음을 의미했습니다. 그들이 한 모든 변경 사항은 5분 내에 자동으로 Sanity에 동기화되었습니다.

Phase 2: 병렬 배포 (주 4-8)

우리는 Next.js 사이트를 서브도메인 (next.finedge.com)에 배포하고 두 사이트를 동시에 실행했습니다. 우리의 QA 프로세스는 모든 단일 페이지를 비교했습니다:

  • Playwright를 통한 200개 이상의 중요 페이지에 대한 시각적 회귀 테스트
  • SEO 동등성 확인 (메타 태그, 구조화된 데이터, 정규 URL, 사이트맵)
  • 모든 페이지 템플릿에 대한 성능 벤치마크
  • 접근성 감사 (WCAG 2.1 AA — 금융 서비스에 필수)

Phase 3: 전환 (주 9)

실제 전환은 지루했습니다 — 정확히 원하는 것입니다. 우리는 Cloudflare의 로드 밸런싱을 사용하여 트래픽을 점진적으로 이동했습니다:

  • 시간 0: 트래픽의 5%는 Next.js로, 95%는 WordPress로
  • 시간 2: 25% / 75% (오류율, Core Web Vitals 모니터링)
  • 시간 6: 50% / 50%
  • 시간 12: 90% / 10%
  • 시간 24: 100% Next.js, WordPress는 읽기 전용 모드
  • 주 2: WordPress 폐기

오류 0개. 다운타임 0개. 모니터링 대시보드는 지루하게 초록색이었습니다.

성능 결과: 3배 빨라짐과 그 이상

Google CrUX 데이터와 Vercel Analytics를 사용하여 마이그레이션 후 30일에 측정한 실제 수치입니다:

메트릭 WordPress (이전) Next.js (이후) 개선
LCP (p75) 5.1s 1.2s 4.25배 빠름
FID / INP (p75) 280ms 68ms 4.1배 빠름
CLS (p75) 0.18 0.02 9배 개선
TTFB (p75) 1.8s 0.12s 15배 빠름
Lighthouse Performance 34 96 +62점
CWV 통과 페이지 32% 98% +66%
상호작용까지의 시간 6.8s 1.4s 4.9배 빠름

"3배 빠름" 헤드라인은 실제로 과소평가합니다. 대부분의 메트릭에서 우리는 4-5배 개선을 봤습니다. TTFB는 스타였습니다 — Vercel의 Edge Network와 ISR (Incremental Static Regeneration) 덕분에 1.8초에서 120밀리초로 이동했습니다.

유기 트래픽은 마이그레이션 후 처음 90일에 31% 증가했습니다. 그들의 SEO 팀은 이를 주로 Core Web Vitals 개선 및 Googlebot의 더 빠른 크롤링 속도에 돌렸습니다.

$420K 라이선스 절약 분석

돈을 이야기해봅시다. $420K가 정확히 어디로 갔는지, 무엇이 그것을 대체했는지:

항목 WordPress 연간 비용 Next.js 연간 비용 절약
WP Engine 엔터프라이즈 호스팅 $150,000 $150,000
Vercel Pro (Team plan) $2,400
프리미엄 플러그인 라이선스 (47개 플러그인) $28,000 $28,000
Sanity Growth plan $1,188
Cloudinary Pro $2,388
엔터프라이즈 WAF (Sucuri) $36,000 $36,000
Cloudflare Pro $2,400
맞춤 WordPress 유지 관리 계약 $96,000 $96,000
CDN (WP Engine과 별도) $24,000 $24,000
스테이징 환경 호스팅 $18,000 $18,000
WordPress 보안 감사 (분기별) $48,000 $48,000
DevOps 팀 시간 (부분 FTE) $120,000 $30,000 $90,000
합계 $520,000 $38,376 $481,624

실제 절약은 $420K가 아니라 대략 $482K에 더 가까웠습니다. 발견 단계의 원래 $420K 추정치는 보수적이었습니다 — 우리는 처음에 DevOps 시간 감소나 분기별 보안 감사 제거를 설명하지 않았습니다 (Vercel과 Cloudflare는 해당 감사가 다루었던 대부분을 처리합니다).

ROI 수학은 간단합니다. 우리의 마이그레이션 프로젝트는 10주 참여 기간에 FinEdge에 대략 $185K의 에이전시 비용이 들었습니다. 그 투자는 5개월 미만에 스스로를 지불했습니다.

기술 심층 분석: 주요 구현 세부사항

ISR을 통한 2,400개의 블로그 게시물 처리

우리는 빌드 시간에 모든 2,400개의 블로그 게시물을 정적 생성하지 않았습니다. 이는 배포를 고통스럽게 느리게 만들었을 것입니다. 대신, 우리는 온디맨드 재검증과 함께 ISR을 사용했습니다:

// app/blog/[slug]/page.tsx
import { sanityFetch } from '@/lib/sanity'
import { postQuery } from '@/lib/queries'

export const revalidate = 3600 // 폴백으로 매시간 재검증

export async function generateStaticParams() {
  // 트래픽별 상위 100개의 게시물만 사전 생성
  const topPosts = await sanityFetch({
    query: `*[_type == "post"] | order(pageViews desc) [0...100] { "slug": slug.current }`
  })
  return topPosts.map((post) => ({ slug: post.slug }))
}

export default async function BlogPost({ params }) {
  const post = await sanityFetch({
    query: postQuery,
    params: { slug: params.slug },
    tags: [`post:${params.slug}`]
  })
  
  // ... 게시물 렌더링
}

콘텐츠 편집자가 Sanity에서 발행하거나 업데이트할 때, webhook은 우리의 재검증 끝점을 누릅니다:

// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache'
import { NextRequest } from 'next/server'

export async function POST(req: NextRequest) {
  const body = await req.json()
  const secret = req.headers.get('x-sanity-webhook-secret')
  
  if (secret !== process.env.SANITY_WEBHOOK_SECRET) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }
  
  // 특정 콘텐츠 재검증
  if (body._type === 'post') {
    revalidateTag(`post:${body.slug.current}`)
    revalidateTag('posts-list')
  }
  
  return Response.json({ revalidated: true })
}

콘텐츠 업데이트는 이제 실시간 사이트에 3초 미만 내에 나타납니다. WordPress + WP Rocket의 4분 캐시 무효화와 비교해보세요.

고객 포털의 인증

포털 경로에는 Server-side authentication이 필요했습니다. 우리는 Next.js 미들웨어를 그들의 기존 Auth0 설정과 결합했습니다:

// middleware.ts
import { NextResponse } from 'next/server'
import { getSession } from '@auth0/nextjs-auth0/edge'

export async function middleware(req) {
  if (req.nextUrl.pathname.startsWith('/portal')) {
    const session = await getSession(req, NextResponse.next())
    
    if (!session?.user) {
      return NextResponse.redirect(new URL('/api/auth/login', req.url))
    }
  }
  
  return NextResponse.next()
}

export const config = {
  matcher: ['/portal/:path*']
}

이것은 엣지에서 실행되므로 인증되지 않은 요청은 애플리케이션 서버에 도달하기 전에 리다이렉트됩니다. 빠르고 안전합니다.

301 리다이렉트 맵

마이그레이션 중에 구조가 변경된 대략 340개의 URL이 있었습니다. 금융 서비스 사이트는 절대 깨진 링크를 가질 수 없습니다 — 규제 제출, 파트너 사이트, 역사적 콘텐츠로부터의 모든 인바운드 링크가 올바르게 해결되어야 합니다.

우리는 next.config.js에 리다이렉트 맵을 구축하고 편집자가 관리하는 리다이렉트에 대해 Sanity의 동적 리다이렉트 조회로 보충했습니다:

// next.config.js (부분)
module.exports = {
  async redirects() {
    return [
      // 알려진 URL 변경에 대한 정적 리다이렉트
      ...require('./redirects.json').map(r => ({
        source: r.from,
        destination: r.to,
        permanent: true,
      })),
    ]
  },
}

출시 후 6개월, Google Search Console은 마이그레이션으로부터의 404 오류를 0개 표시합니다. 모든 단일 리다이렉트가 작동하고 있습니다.

어렵게 배운 교훈

1. WordPress Gutenberg 블록은 변환하기가 어렵습니다

Gutenberg 블록을 Sanity의 Portable Text로 변환하는 노력을 과소평가했습니다. FinEdge는 이전 에이전시가 구축한 맞춤 블록을 포함하여 23개의 다양한 블록 유형을 사용했습니다. 콘텐츠 변환을 위해 생각하는 것보다 최소 20% 더 많은 시간을 예산하세요.

2. 콘텐츠 편집자 교육은 선택 사항이 아닙니다

Sanity의 Studio는 직관적이지만, WordPress가 아닙니다. 우리는 3개의 90분 교육 세션을 실행했고 가이드 워크플로우가 있는 맞춤 Sanity Studio를 만들었습니다. 콘텐츠 팀은 2주 내에 회의적에서 열정적으로 이동했지만, 그 교육 투자는 중요했습니다.

3. 금융 서비스 규정 준수는 복잡성을 더합니다

모든 배포에는 감시 증적이 필요했습니다. 모든 콘텐츠 변경을 타임스탬프 및 사용자 귀속과 함께 로깅해야 했습니다. 우리는 모든 문서 변경을 해당 기존 PostgreSQL 데이터베이스의 append-only 감시 테이블에 로깅하는 맞춤 Sanity 플러그인을 구축했습니다. 이는 원래 범위에 없었던 추가 1주일을 걸렸습니다.

4. 양식을 잊지 마세요

Gravity Forms는 WordPress 사이트의 14개의 다양한 양식 유형을 처리하고 있었습니다. 우리는 그들을 React Hook Form + Zod validation이 있는 프론트엔드와 백엔드의 서버 작업으로 대체했으며, 제출은 그들의 기존 HubSpot CRM으로 가고 있었습니다. 이 마이그레이션만 해도 전체 1주일이 걸렸습니다.

일정과 팀 구조

전체 프로젝트 기간: 10주

포커스
1 아키텍처, Sanity 스키마 설계, 콘텐츠 감사 2명의 개발자, 1명의 아키텍트
2-3 콘텐츠 동기화 파이프라인, Sanity Studio 맞춤화 2명의 개발자, 1명의 콘텐츠 전략가
4-5 마케팅 사이트 구축 (Next.js) 3명의 개발자
6-7 포털 마이그레이션, 인증, 양식 3명의 개발자
8 문서 허브, SEO 감사, 리다이렉트 맵 2명의 개발자, 1명의 SEO 전문가
9 QA, 시각적 회귀, 성능 테스트 2명의 개발자, 1명의 QA
10 점진적 트래픽 전환, 모니터링, WordPress 폐기 2명의 개발자, 1명의 DevOps

최대 팀 규모는 4명이었습니다. 프로젝트의 대부분은 2-3명의 개발자로 실행되었습니다. 이것은 15명의 팀, 6개월 참여가 아닙니다 — 이것은 잘 계획된 마이그레이션을 실행하는 집중된 경험 있는 팀입니다.

조직에 대해 유사한 마이그레이션을 고려하고 있다면, 우리는 우리의 헤드리스 CMS 개발 접근 방식을 문서화했고 우리의 가격 책정 구조는 투명합니다. 우리는 또한 당신의 특정 상황을 이야기하기 위해 전화를 받는 것을 기꺼이 합니다 — 여기에서 연락하세요.

자주 묻는 질문

WordPress에서 Next.js로의 마이그레이션은 일반적으로 얼마나 걸립니까? 이런 복잡성의 사이트 (12,000개 페이지, 고객 포털, 문서 허브)의 경우, 경험이 풍부한 팀으로 10주가 현실적입니다. 더 간단한 마케팅 사이트 (100-500개 페이지)는 4-6주에 마이그레이션할 수 있습니다. 가장 큰 변수는 콘텐츠 복잡성입니다 — 당신이 실행하는 사용자 지정 게시물 유형, 블록 유형, 플러그인 종속 기능이 얼마나 많은지입니다.

WordPress를 다운타임 없이 Next.js로 마이그레이션할 수 있습니까? 예, 하지만 계획이 필요합니다. 핵심은 콘텐츠 동기화 파이프라인과 함께 두 시스템을 병렬로 실행한 다음, DNS 수준의 트래픽 이동을 사용하여 사용자를 새 사이트로 점진적으로 이동하는 것입니다. 우리는 여러 클라이언트에 대해 이를 성공적으로 했습니다. 중요한 요구사항은 전환 기간 동안 콘텐츠가 두 시스템 모두에서 동기화 상태로 유지되어야 한다는 것입니다.

WordPress에서 헤드리스 CMS로의 마이그레이션 비용은 얼마입니까? 범위에 따라 크게 달라집니다. 간단한 마케팅 사이트 마이그레이션은 $30K-$60K일 수 있습니다. FinEdge와 같은 엔터프라이즈 마이그레이션 — 고객 포털, 규정 준수 요구사항, 12,000개 페이지가 있는 — 는 $185K였습니다. 절대 비용보다 ROI 계산이 더 중요합니다. FinEdge의 투자는 라이선스 절약만으로 5개월 미만에 스스로를 지불했습니다.

Next.js가 실제로 WordPress보다 빠릅니까? 실질적으로 모든 경우에, 예 — 상당히 빠릅니다. WordPress는 각 요청에 대해 HTML을 생성합니다 (무거운 캐싱이 없다면), 그리고 WP Rocket과 같은 캐싱 플러그인으로도, 당신은 PHP의 응답 시간과 WordPress 생태계의 무게에 의해 제한됩니다. Next.js는 ISR 또는 정적 생성을 통해 엣지에서 사전 구축된 페이지를 제공합니다. 우리는 일반적으로 Core Web Vitals에서 3-5배 개선을 봅니다.

Next.js와 함께 어떤 헤드리스 CMS를 사용해야 합니까? 팀과 요구사항에 따라 달라집니다. Sanity는 맞춤 콘텐츠 모델링 및 실시간 협력에서 탁월합니다. Contentful은 더 구조화되고 의견이 강한 접근 방식을 원하는 엔터프라이즈 팀에 강점이 있지만 seat별로 비싸집니다. Storyblok은 시각적 편집이 우선순위인 경우 훌륭합니다. 더 간단한 사이트의 경우, Git 리포지토리의 마크다운 파일도 작동할 수 있습니다. 우리는 프로젝트별로 이를 평가합니다 — 보편적인 답변은 없습니다.

WordPress에서 Next.js로 마이그레이션할 때 SEO를 잃습니까? 올바르게 수행하면 아닙니다. 중요한 세 가지: 기존 URL이 404를 반환하지 않도록 종합 301 리다이렉트 매핑, 모든 메타 태그 및 구조화된 데이터 보존, 그리고 전환 직후 Google Search Console에 업데이트된 사이트맵 제출입니다. FinEdge는 주로 Core Web Vitals 개선에 의해 주도되는 마이그레이션 후 90일 내에 유기 트래픽이 31% 증가했습니다.

마이그레이션 후 WordPress 플러그인은 어떻게 됩니까? 각 플러그인의 기능을 복제하거나 대체해야 합니다. 일부는 간단합니다 — SEO 플러그인은 Next.js 컴포넌트의 메타데이터로 대체되고, 캐싱 플러그인은 불필요해지고, 양식 플러그인은 React 양식 라이브러리로 대체됩니다. 다른 경우들, 예를 들어 맞춤 규정 준수 로깅 플러그인 같은, 맞춤 교체 코드가 필요합니다. 이것이 발견 단계에서 철저한 플러그인 감사가 필수인 이유입니다.

헤드리스로 이동한 후 콘텐츠 편집자가 여전히 시각적 편집기를 사용할 수 있습니까? 예. Sanity Studio는 실시간 미리보기가 있는 맞춤 편집 인터페이스를 제공합니다. 이것은 WordPress의 블록 편집기와 다르지만, 초기 학습 곡선 후 대부분의 콘텐츠 팀이 그것을 선호합니다. Sanity의 Presentation 도구는 이제 실시간 미리보기에서 클릭-편집 기능이 있는 진정한 시각적 편집을 제공합니다. 우리는 또한 Vercel의 미리보기 배포를 설정하여 편집자가 게시하기 전에 정확히 그들의 콘텐츠가 어떻게 보일 것인지 볼 수 있습니다.