The Challenge
When Next.js introduced its data fetching methods — getStaticProps for Static Site Generation and getServerSideProps for Server Side Rendering — I wanted to build a practical example that demonstrated both approaches side by side. The goal was to create a project that would help me (and other developers) understand the trade-offs between SSG and SSR in a real application, not just a tutorial snippet.
I chose the PokéAPI as the data source because it provides a rich, well-documented REST API with hundreds of entries — perfect for testing pagination, dynamic routes, and image optimization at scale.
The Solution
The Pokédex app fetches data from the PokéAPI and renders a browsable catalog of Pokémon. The key architectural decision was implementing a toggle between SSG and SSR rendering strategies:
- Static Site Generation (SSG): All Pokémon pages are pre-rendered at build time using
getStaticPropsandgetStaticPaths. This produces fast, CDN-cacheable HTML pages with near-instant load times. - Server Side Rendering (SSR): The same pages can be rendered on-demand per request using
getServerSideProps, which is useful when data changes frequently or when there are too many pages to pre-build.
The toggle is implemented at the routing level, allowing a direct comparison of the same content rendered by each strategy.
Key Technical Decisions
- Next.js 10 Image Component: Used the built-in
next/imagefor automatic image optimization, lazy loading, and responsive sizing of Pokémon sprites. This reduced total image transfer significantly compared to raw<img>tags. - Dynamic Routes: Each Pokémon has its own page at
/pokemon/[id], generated statically for the SSG path and server-rendered for the SSR path. - TailwindCSS with Dark Mode: Built the entire UI with Tailwind v2, including a dark mode toggle using Tailwind’s
dark:variant — one of the first projects where I used this feature. - Serverless Deployment: Deployed to Vercel, taking advantage of serverless functions for the SSR path and edge-cached static pages for the SSG path.
What I Learned
This project solidified my understanding of when to use each rendering strategy. SSG is ideal for content that rarely changes and benefits from edge caching, while SSR is necessary when content must be fresh on every request. In practice, most applications benefit from a hybrid approach — something that frameworks like Next.js handle well with incremental static regeneration (ISR).



Credits
Thanks to everyone at PokéAPI for making the data freely available. Pokémon and Pokémon character names are trademarks of Nintendo.