{"schemaVersion":1,"id":"https://lucioduran.com/es/decisions/isr-ready-architecture","url":"https://lucioduran.com/es/decisions/isr-ready-architecture","title":"ISR-Ready Architecture with Full Static Fallback","description":"Incremental Static Regeneration (ISR) is a Next.js feature that allows static pages to be revalidated after deployment without a full rebuild. For a portfolio w","language":"en","datePublished":null,"dateModified":null,"contentFormat":"text/markdown","content":"ADR-010accepted18 de junio de 2024\n\n# ISR-Ready Architecture with Full Static Fallback\n\n## Contexto\n\nIncremental Static Regeneration (ISR) is a Next.js feature that allows static pages to be revalidated after deployment without a full rebuild. For a portfolio with infrequently changing content, ISR could eliminate the rebuild-redeploy cycle for content updates, pages would regenerate in the background when stale. However, ISR introduces runtime complexity: it requires a serverless function layer (Vercel Functions) that runs on-demand, adds a stale-while-revalidate caching behavior that can serve outdated content during regeneration, and creates a dependency on Vercel's ISR infrastructure availability. If ISR fails silently, pages could serve stale data indefinitely. The site must function correctly with pure static generation as the baseline.\n\n## Decisión\n\nDesign the data-fetching architecture to be ISR-compatible but deploy with full static generation as the default. All getStaticProps functions are structured to accept a revalidate parameter that is currently commented out. The data-fetching patterns use standard HTTP requests that work identically whether called at build time (SSG) or at revalidation time (ISR). No getStaticProps function depends on build-time-only context (like environment variables that differ between build and runtime). The architecture is ready to enable ISR by uncommenting a single revalidate property per page, but currently runs as pure SSG with zero serverless function invocations.\n\n## Consecuencias\n\nPositive: The site operates with maximum resilience, static HTML served from CDN edge with no runtime dependencies. If Vercel's serverless infrastructure experiences issues, the site is unaffected because no serverless functions are invoked. When content freshness becomes a priority (e.g., frequent portfolio updates), ISR can be enabled per-page by adding \\`revalidate: 3600\\` to any getStaticProps, no architectural changes required. The cost is zero serverless function invocations on the current plan. Negative: Content updates require a manual redeploy, adding ~90 seconds of latency between publishing content and it appearing on the site. The commented-out revalidate properties are a form of dead code that could confuse future contributors. The ISR-ready constraint means getStaticProps cannot use any build-time-only APIs or file system operations that wouldn't be available in the serverless runtime. This is a resilience-first architecture: the site trades content freshness for operational simplicity and infrastructure independence.\n\n## Incertidumbre Calibrada\n\n## Predicciones al Momento de la Decisión\n\nExpected the ISR-ready constraint to be cost-free, predicted that no getStaticProps function would need build-time-only context. Predicted ISR would eventually be activated when content updates became frequent enough to justify it (estimated threshold: daily updates). Assumed the commented-out revalidate parameters would serve as clear documentation of ISR-readiness.\n\n## Resultados Medidos\n\nThe ISR-ready constraint has been cost-free as predicted, no getStaticProps function needed build-time-only context, and the local JSON import for ADRs (ADR-008) works identically in SSG and ISR modes. ISR has not been activated because content update frequency has not reached the daily threshold, updates cluster in bursts (multiple per day during active development, then weeks of stability). The commented-out revalidate parameters exist in API-fetching pages but are less relevant for the ADR pages that use local imports. The 90-second redeploy cycle remains acceptable. The unexpected outcome: the discipline of ISR-readiness prevented a potential architectural mistake when adding local JSON imports, the pattern is explicitly compatible with both SSG and ISR, not just SSG.\n\n## Incógnitas al Momento de la Decisión\n\nDid not know whether Next.js would introduce a better alternative to ISR. Next.js 15's App Router with server components represents a different paradigm entirely, one where the SSG/SSR/ISR distinction is less relevant. If the site migrates to App Router, the ISR-ready constraint becomes moot. Also unknown: whether Vercel would introduce usage-based pricing changes that make ISR's serverless invocations a cost concern. The zero-cost guarantee of pure SSG is a financial hedge that ISR cannot match.\n\n## Clasificación de Reversibilidad\n\nPuerta de Ida y Vuelta\n\nActivating ISR requires uncommenting revalidate properties in getStaticProps, a one-line change per page. Deactivating ISR requires re-commenting them. The entire toggle between SSG and ISR is a configuration change with zero code modifications. Estimated effort to activate: 30 minutes for all pages plus testing. Estimated effort to deactivate: 15 minutes. This is the most reversible decision in the entire architecture.\n\n## Contra-Argumento Más Fuerte\n\nThe ISR-ready architecture adds invisible complexity: future developers must understand why getStaticProps functions are written in a specific way (no build-time-only context) without the constraint being visible in the code. The commented-out revalidate parameters are dead code by any linting standard. A simpler approach: build with pure SSG, no ISR considerations, and refactor when ISR is actually needed. The refactoring cost is low (each page is independent), so the pre-optimization is arguably YAGNI. The counter-counter: the constraint is not a cost, it's a discipline that prevents architectural drift and keeps future options open at zero marginal effort.\n\n## Contexto Técnico\n\nStack\n\n- Next.js 15\n- Vercel\n- getStaticProps\n- Edge Network\n\nServerless Functions\n\n0\n\nRedeploy Time\n\n~90 seconds\n\nIsr Ready Pages\n\nAll content pages\n\nMonthly Cost\n\n$0 (free tier, no serverless invocations)\n\nRestricciones\n\n- No build-time-only dependencies in getStaticProps\n- Pure static as default\n- ISR activation requires only config change\n\n## Decisiones Relacionadas\n\n- [ADR-001accepted\n\n  Static Site Generation over Server-Side Rendering](<https://lucioduran.com/es/decisions/ssg-over-ssr>)\n- [ADR-005accepted\n\n  Decoupled API Architecture](<https://lucioduran.com/es/decisions/decoupled-api-architecture>)\n- [ADR-008accepted\n\n  Static JSON over CMS for Decision Records](<https://lucioduran.com/es/decisions/static-json-over-cms>)\n- [ADR-013accepted\n\n  Zero-Downtime Deploy Strategy with Atomic Rollouts](<https://lucioduran.com/es/decisions/zero-downtime-deploy-strategy>)\n\n[Volver a Decisiones](<https://lucioduran.com/es/decisions>)","headings":[{"level":1,"text":"ISR-Ready Architecture with Full Static Fallback","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#title"},{"level":2,"text":"Contexto","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-context"},{"level":2,"text":"Decisión","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-decision"},{"level":2,"text":"Consecuencias","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-consequences"},{"level":2,"text":"Incertidumbre Calibrada","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-uncertainty"},{"level":2,"text":"Predicciones al Momento de la Decisión","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-predictions"},{"level":2,"text":"Resultados Medidos","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-outcomes"},{"level":2,"text":"Incógnitas al Momento de la Decisión","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-unknowns"},{"level":2,"text":"Clasificación de Reversibilidad","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-reversibility"},{"level":2,"text":"Contra-Argumento Más Fuerte","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-counterArgument"},{"level":2,"text":"Contexto Técnico","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-techContext"},{"level":2,"text":"Decisiones Relacionadas","url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-relatedDecisions"}],"sections":[{"heading":"ISR-Ready Architecture with Full Static Fallback","level":1,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture","content":"ADR-010accepted18 de junio de 2024"},{"heading":"ISR-Ready Architecture with Full Static Fallback","level":1,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#title","content":""},{"heading":"Contexto","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-context","content":"Incremental Static Regeneration (ISR) is a Next.js feature that allows static pages to be revalidated after deployment without a full rebuild. For a portfolio with infrequently changing content, ISR could eliminate the rebuild-redeploy cycle for content updates, pages would regenerate in the background when stale. However, ISR introduces runtime complexity: it requires a serverless function layer (Vercel Functions) that runs on-demand, adds a stale-while-revalidate caching behavior that can serve outdated content during regeneration, and creates a dependency on Vercel's ISR infrastructure availability. If ISR fails silently, pages could serve stale data indefinitely. The site must function correctly with pure static generation as the baseline."},{"heading":"Decisión","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-decision","content":"Design the data-fetching architecture to be ISR-compatible but deploy with full static generation as the default. All getStaticProps functions are structured to accept a revalidate parameter that is currently commented out. The data-fetching patterns use standard HTTP requests that work identically whether called at build time (SSG) or at revalidation time (ISR). No getStaticProps function depends on build-time-only context (like environment variables that differ between build and runtime). The architecture is ready to enable ISR by uncommenting a single revalidate property per page, but currently runs as pure SSG with zero serverless function invocations."},{"heading":"Consecuencias","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-consequences","content":"Positive: The site operates with maximum resilience, static HTML served from CDN edge with no runtime dependencies. If Vercel's serverless infrastructure experiences issues, the site is unaffected because no serverless functions are invoked. When content freshness becomes a priority (e.g., frequent portfolio updates), ISR can be enabled per-page by adding \\`revalidate: 3600\\` to any getStaticProps, no architectural changes required. The cost is zero serverless function invocations on the current plan. Negative: Content updates require a manual redeploy, adding ~90 seconds of latency between publishing content and it appearing on the site. The commented-out revalidate properties are a form of dead code that could confuse future contributors. The ISR-ready constraint means getStaticProps cannot use any build-time-only APIs or file system operations that wouldn't be available in the serverless runtime. This is a resilience-first architecture: the site trades content freshness for operational simplicity and infrastructure independence."},{"heading":"Incertidumbre Calibrada","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-uncertainty","content":""},{"heading":"Predicciones al Momento de la Decisión","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-predictions","content":"Expected the ISR-ready constraint to be cost-free, predicted that no getStaticProps function would need build-time-only context. Predicted ISR would eventually be activated when content updates became frequent enough to justify it (estimated threshold: daily updates). Assumed the commented-out revalidate parameters would serve as clear documentation of ISR-readiness."},{"heading":"Resultados Medidos","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-outcomes","content":"The ISR-ready constraint has been cost-free as predicted, no getStaticProps function needed build-time-only context, and the local JSON import for ADRs (ADR-008) works identically in SSG and ISR modes. ISR has not been activated because content update frequency has not reached the daily threshold, updates cluster in bursts (multiple per day during active development, then weeks of stability). The commented-out revalidate parameters exist in API-fetching pages but are less relevant for the ADR pages that use local imports. The 90-second redeploy cycle remains acceptable. The unexpected outcome: the discipline of ISR-readiness prevented a potential architectural mistake when adding local JSON imports, the pattern is explicitly compatible with both SSG and ISR, not just SSG."},{"heading":"Incógnitas al Momento de la Decisión","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-unknowns","content":"Did not know whether Next.js would introduce a better alternative to ISR. Next.js 15's App Router with server components represents a different paradigm entirely, one where the SSG/SSR/ISR distinction is less relevant. If the site migrates to App Router, the ISR-ready constraint becomes moot. Also unknown: whether Vercel would introduce usage-based pricing changes that make ISR's serverless invocations a cost concern. The zero-cost guarantee of pure SSG is a financial hedge that ISR cannot match."},{"heading":"Clasificación de Reversibilidad","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-reversibility","content":"Puerta de Ida y Vuelta\n\nActivating ISR requires uncommenting revalidate properties in getStaticProps, a one-line change per page. Deactivating ISR requires re-commenting them. The entire toggle between SSG and ISR is a configuration change with zero code modifications. Estimated effort to activate: 30 minutes for all pages plus testing. Estimated effort to deactivate: 15 minutes. This is the most reversible decision in the entire architecture."},{"heading":"Contra-Argumento Más Fuerte","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-counterArgument","content":"The ISR-ready architecture adds invisible complexity: future developers must understand why getStaticProps functions are written in a specific way (no build-time-only context) without the constraint being visible in the code. The commented-out revalidate parameters are dead code by any linting standard. A simpler approach: build with pure SSG, no ISR considerations, and refactor when ISR is actually needed. The refactoring cost is low (each page is independent), so the pre-optimization is arguably YAGNI. The counter-counter: the constraint is not a cost, it's a discipline that prevents architectural drift and keeps future options open at zero marginal effort."},{"heading":"Contexto Técnico","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-techContext","content":"Stack\n\n- Next.js 15\n- Vercel\n- getStaticProps\n- Edge Network\n\nServerless Functions\n\n0\n\nRedeploy Time\n\n~90 seconds\n\nIsr Ready Pages\n\nAll content pages\n\nMonthly Cost\n\n$0 (free tier, no serverless invocations)\n\nRestricciones\n\n- No build-time-only dependencies in getStaticProps\n- Pure static as default\n- ISR activation requires only config change"},{"heading":"Decisiones Relacionadas","level":2,"url":"https://lucioduran.com/es/decisions/isr-ready-architecture#decisionDetail-relatedDecisions","content":"- [ADR-001accepted\n\n  Static Site Generation over Server-Side Rendering](<https://lucioduran.com/es/decisions/ssg-over-ssr>)\n- [ADR-005accepted\n\n  Decoupled API Architecture](<https://lucioduran.com/es/decisions/decoupled-api-architecture>)\n- [ADR-008accepted\n\n  Static JSON over CMS for Decision Records](<https://lucioduran.com/es/decisions/static-json-over-cms>)\n- [ADR-013accepted\n\n  Zero-Downtime Deploy Strategy with Atomic Rollouts](<https://lucioduran.com/es/decisions/zero-downtime-deploy-strategy>)\n\n[Volver a Decisiones](<https://lucioduran.com/es/decisions>)"}],"links":[{"text":"ADR-001acceptedStatic Site Generation over Server-Side Rendering","url":"https://lucioduran.com/es/decisions/ssg-over-ssr"},{"text":"ADR-005acceptedDecoupled API Architecture","url":"https://lucioduran.com/es/decisions/decoupled-api-architecture"},{"text":"ADR-008acceptedStatic JSON over CMS for Decision Records","url":"https://lucioduran.com/es/decisions/static-json-over-cms"},{"text":"ADR-013acceptedZero-Downtime Deploy Strategy with Atomic Rollouts","url":"https://lucioduran.com/es/decisions/zero-downtime-deploy-strategy"},{"text":"Volver a Decisiones","url":"https://lucioduran.com/es/decisions"}],"structuredData":[{"@context":"https://schema.org/","@graph":[{"@type":"TechArticle","url":"https://lucioduran.com/es/decisions/isr-ready-architecture","name":"ADR-010: ISR-Ready Architecture with Full Static Fallback","headline":"ISR-Ready Architecture with Full Static Fallback","datePublished":"2024-06-18","author":{"@id":"https://lucioduran.com/#person"},"isPartOf":{"@id":"https://lucioduran.com/#website"},"inLanguage":"en","about":"Software Architecture Decision Record","proficiencyLevel":"Expert","dependencies":"Next.js 15, Vercel, getStaticProps, Edge Network"},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https://lucioduran.com/"},{"@type":"ListItem","position":2,"name":"Decisiones de Arquitectura","item":"https://lucioduran.com/es/decisions"},{"@type":"ListItem","position":3,"name":"ISR-Ready Architecture with Full Static Fallback"}]}]}],"contentHash":"34ded7f8ced0bdac3eec8a189cbb5ac8ba649b2c4c28e05c85f18f3eb80d7bfe","provenance":{"method":"Deterministic serialization of the server-rendered main element","source":"https://lucioduran.com/es/decisions/isr-ready-architecture","hashAlgorithm":"sha256","hashScope":"JSON document fields before contentHash and provenance","sourceHTMLBytes":38121,"contentBytes":6553}}
