इसके साथ संबद्ध Testlify

Testlify - Next.js पर मार्केटिंग साइट माइग्रेशन

एक 11,000+ पेज की मार्केटिंग साइट के लिए WordPress को कैश-फर्स्ट Next.js 16 आर्किटेक्चर से बदलने का आर्किटेक्चरल फ़ैसला लीड किया, मौजूदा SEO अथॉरिटी बचाने के लिए पेज-दर-पेज प्रोडक्शन के खिलाफ वेरिफाई किया।

Testlify की मार्केटिंग साइट में 11,000 से ज़्यादा पेज हैं। पुराने WordPress सेटअप में हर रिक्वेस्ट पर सर्वर-साइड रेंडरिंग ओवरहेड और प्लगइन बॉटलनेक थे, जो पेज लोड स्पीड और सर्च इंजन रैंकिंग को प्रभावित करते थे। मैंने साइट को Next.js 16 पर माइग्रेट करने का आर्किटेक्चरल फ़ैसला लीड किया, और यह रोलआउट फ़िलहाल जारी है।

आर्किटेक्चरल फ़ैसला

  • WordPress की बजाय कैश-फर्स्ट: पेज पहली रिक्वेस्ट पर एक बार रेंडर होते हैं और अनिश्चित काल तक कैश रहते हैं, हर रिक्वेस्ट पर डेटाबेस हिट करने या 11,000+ पेजों के लिए घंटों की बैच रीबिल्ड की ज़रूरत की बजाय। एक Payload CMS वेबहुक सिर्फ़ उन्हीं पेजों को इनवैलिडेट करता है जिन्हें कोई कंटेंट बदलाव असल में प्रभावित करता है।
  • हेडलेस CMS इंटीग्रेशन: कंटेंट Payload CMS के ज़रिए मैनेज होता है, जो Postgres पर बैक्ड एक सेल्फ-होस्टेड हेडलेस CMS है, जिससे मार्केटिंग टीमें पेज एडिट और पब्लिश कर सकती हैं जबकि कैश-इनवैलिडेशन हुक्स हर बदलाव को ऑटोमेटिकली पकड़ लेते हैं।
  • स्केल पर माइग्रेशन: 11,000+ पेजों का स्टेज्ड माइग्रेशन प्लान और एग्ज़िक्यूट किया, प्रोडक्शन के लाइव साइटमैप के खिलाफ पेज-दर-पेज वेरिफाई किया, सभी कैटेगरी में URL स्ट्रक्चर, कैनोनिकल टैग, और मौजूदा SEO अथॉरिटी बरकरार रखते हुए।

यह क्यों मायने रखता था

11,000+ पेजों वाली साइट को WordPress से एक कैश-फर्स्ट आर्किटेक्चर पर ले जाने से पेज लोड टाइम घटता है, टेक्निकल SEO परफॉर्मेंस बेहतर होती है, और मार्केटिंग टीमें इंजीनियरिंग डिप्लॉयमेंट पर निर्भर हुए बिना अपडेट पब्लिश कर पाती हैं।

ओनरशिप, अभी भी जारी

मैंने WordPress से हटने का आर्किटेक्चरल फ़ैसला लीड किया। यह सोलो बिल्ड नहीं है: जुलाई 2026 से लगभग 15-20 योगदानकर्ताओं के 2,500 से ज़्यादा कमिट्स, इसी महीने तक एक्टिव, आखिरी स्टेटस चेक तक प्रोडक्शन पर DNS कटओवर एकमात्र बचा कदम है।

यह क्लासिक Jamstack क्यों नहीं है

11,000+ पेजों के लिए जो साफ़ तरीका दिखता है वह है बिल्ड-टाइम पर स्टैटिक जनरेशन। यह यहां फ़िट नहीं बैठता: हर लोकेल और कंटेंट टाइप में एक पूरी रीबिल्ड घंटों लेगी, और एक कंटेंट एडिट के लिए पूरी साइट को लाइव करने के लिए रीबिल्ड की ज़रूरत नहीं होनी चाहिए। इसकी बजाय, हर डायनामिक रूट (category, author, hr-tools, hr-guide, blog, test-library, और भी) एक ही कन्वेंशन फॉलो करता है: बिल्ड हर रूट टाइप का सिर्फ़ एक सैंपल पेज प्री-रेंडर करता है, क्योंकि Cache Components को बिल्ड करने के लिए कम से कम एक पैरामीटर चाहिए और खुद बिल्ड में ज़ीरो डेटाबेस क्वेरी चलनी चाहिए। उस रूट के तहत बाकी हर पेज अपनी पहली असली रिक्वेस्ट पर Next.js 16 के Cache Components के तहत रेंडर होता है, फिर अनिश्चित काल तक कैश्ड रहता है (cacheLife को Next के अपने INFINITE_CACHE कॉन्स्टेंट पर सेट किया गया है) जब तक कि Payload CMS का afterChange हुक उस स्पेसिफिक पेज के लिए एक साइन किया गया रीवैलिडेशन एंडपॉइंट कॉल न करे। कंटेंट बदलाव सेकंड्स में फैलते हैं, पूरे रीबिल्ड साइकल में नहीं, और कैश फिर भी विज़िटर की तरफ़ से एक CDN एज कैश की तरह बर्ताव करता है। रीवैलिडेशन एंडपॉइंट खुद HMAC-साइन्ड है और कॉन्स्टेंट-टाइम कम्पैरिज़न से चेक होता है, और जानबूझकर एक बार में सिर्फ़ एक टैग इनवैलिडेट करने तक सीमित है: सिर्फ़ एक अलग, मैनुअली-ट्रिगर्ड एडमिन पाथ ही कलेक्शन-वाइड टैग पर्ज कर सकता है, ताकि एक लीक्ड वेबहुक सीक्रेट ज़्यादा से ज़्यादा एक ही पेज इनवैलिडेट कर सके, पूरी साइट के कैश को एक साथ स्टैम्पीड न करे।

दो फ्रेमवर्क बग, प्रोडक्शन में मिले और सोर्स पर फ़िक्स किए गए

बिल्ड के दौरान दो अलग Next.js 16 इश्यू सामने आए, दोनों अब सीधे next.config.ts में डॉक्यूमेंटेड हैं ताकि अगला व्यक्ति इन्हें मुश्किल तरीके से दोबारा न खोजे। पहला, cacheComponents डिफ़ॉल्ट रूप से चुपचाप enablePrerenderSourceMaps ऑन कर देता है, जो स्टैटिक पेज जनरेशन के दौरान प्रोडक्शन बिल्ड को OOM-किल कर रहा था; इसे Next के खुद के सोर्स तक ट्रेस किया गया और एक एक्सप्लिसिट ओवरराइड से फ़िक्स किया गया। दूसरा, कैश लाइफटाइम के लिए Infinity इस्तेमाल करने से वह Next के बिल्ड वर्कर्स तक जाते हुए JSON-सीरियलाइज़ होकर null बन जाता है, जो उस रूट को चुपचाप uncached कर देता है, एरर देने की बजाय, और पकड़े जाने तक हर लोकेल में प्रीरेंडरिंग तोड़ देता है; इसे रॉ Infinity की बजाय Next के अपने INFINITE_CACHE कॉन्स्टेंट का इस्तेमाल करके फ़िक्स किया गया।

एक स्ट्रीमिंग एज केस के लिए एक SEO फ़िक्स

Cache Components की स्ट्रीमिंग के तहत, Next का ऑटोमेटिक notFound() पेज शेल के क्लाइंट को स्ट्रीम होना शुरू होने से पहले 404 HTTP स्टेटस कमिट नहीं कर सकता, इसलिए सिर्फ़ उस शेल को पढ़ने वाला कोई क्रॉलर इसे कभी नहीं देखेगा। इसका फ़िक्स पहले फ्लश में मैनुअली एक noindex डायरेक्टिव इंजेक्ट करता है, ताकि उस शेल पर रुकने वाले क्रॉलर को भी सही सिग्नल मिले, बाकी पेज रिज़ॉल्व होने से पहले ही।

डेटा मॉडल और स्केल

  • 11,000+ पेज कई कंटेंट टाइप्स (category, author, hr-tools, hr-guide, leadership, test-library) से आते हैं जो next-intl के ज़रिए हर सपोर्टेड लोकेल के साथ क्रॉस होते हैं, एक फ्लैट कंटेंट सोर्स नहीं।
  • हर प्रोडक्शन WordPress URL को एक डेडिकेटेड ऑडिट (docs/audits/url-parity-with-production.md) में इस प्रोजेक्ट के आउटपुट के खिलाफ चेक किया जाता है: एक URL जो WordPress आज सर्व करता है और यह प्रोजेक्ट 404 करता है, वह खोया ट्रैफ़िक है, कोई एक्सेप्टेबल गैप नहीं।
  • यूनिट टेस्ट्स (Vitest) साइटमैप जनरेशन, कैटलॉग सीड फॉलबैक, और रिलेटेड-कंटेंट रोटेशन को कवर करते हैं; Playwright एंड-टू-एंड फ्लो कवर करता है।

Build vs. Buy

एक SaaS हेडलेस CMS की बजाय Postgres पर सेल्फ-होस्टेड Payload CMS: कंटेंट ओनरशिप और डेटाबेस को इन-हाउस रखता है, एक मार्केटिंग साइट के लिए per-seat SaaS बिल भरने की बजाय। एक हाथ से बनाई CDN/ISR लेयर की बजाय Next.js के अपने Cache Components और टैग-आधारित इनवैलिडेशन: कैशिंग बिहेवियर फ्रेमवर्क से आता है, इस टीम को खुद बनाने और ऑपरेट करने वाले इंफ्रास्ट्रक्चर की बजाय।

Stack

Next.js 16, React, TypeScript, Postgres पर Payload CMS, लोकलाइज़ेशन के लिए next-intl, यूनिट टेस्ट्स के लिए Vitest, एंड-टू-एंड टेस्ट्स के लिए Playwright, Vercel पर डिप्लॉयड।