Suggested pattern for Next.js catch-all pages with many shared models?

I have a Next.js site that renders multiple catch-all pages, each of which renders several Builder models. Most of the models are shared between them (e.g., header, footer, sidebar). Example pages for me would be:

  • /pages/[[...page]].tsx: generic catch-all template, renders page page model
  • /pages/project/[project].tsx: specific for project page model

Do you have a suggested pattern for how to compose these Next.js pages in such a way that I don’t have to copy/paste the same boilerplate header/footer/sidebar code?

Sounds trivial, but in practice I’ve found it to be fiendishly difficult.

The main problem is that Next.js doesn’t allow you to use getStaticProps inside of _document.js or _app.js, which would be the natural place to put site-wide layout features. So there’s no way for me to fetch my header/footer/etc. section models in the place where they most obviously belong.

I’ve created a set of utility functions that I’m really unsatisfied with that at least attempt to prepare some of the inputs for getStaticProps and getStaticPaths (builder-fetch-content-utils.ts · GitHub). I also created a Layout component with the header/footer/etc., but that component awkwardly needs me to pass in the Builder content fetched at the page-level. It works but it’s all very brittle.

This must be a common use case, so I was wondering what you all have done to address it.

Resharing from @aziz.

Solution can be found in the nextjs-shopify starter, specifically the helper function getLayoutProps: Search · getLayoutProps · GitHub

The missing link that I was unaware of is that _app.js supports something called pageProps, which can be used to pass in prefetched data from a page’s getStaticProps into the app-wide template. So then you can pass in the fetched Builder content to a layout component, like this: nextjs-shopify/_app.tsx at master · BuilderIO/nextjs-shopify · GitHub

Info on pageProps: Advanced Features: Custom `App` | Next.js.

Thanks @aziz!

2 Likes