Skip to content

fix(website): prerender every template page instead of only the first 30 - #180

Open
bariscelik wants to merge 1 commit into
Dokploy:mainfrom
bariscelik:fix/prerender-all-template-pages
Open

fix(website): prerender every template page instead of only the first 30#180
bariscelik wants to merge 1 commit into
Dokploy:mainfrom
bariscelik:fix/prerender-all-template-pages

Conversation

@bariscelik

@bariscelik bariscelik commented Sep 3, 2026

Copy link
Copy Markdown

Problem

On dokploy.com/templates, only the first 30 template pages work. Every other template detail page returns a plain Internal Server Error (HTTP 500).

The /templates listing links to all 518 templates, so 488 of those links are currently dead for both visitors and search engines.

The cutoff is exactly alphabetical position 30:

URL Position Status
/templates/ackee 2 200
/templates/answer 18 200
/templates/argilla 30 200
/templates/audiobookshelf 31 500
/templates/authentik 32 500

Cause

generateStaticParams in app/templates/[id]/page.tsx caps the prerendered set at 30:

return templates.slice(0, 30).map((template) => ({ id: template.id }));

With dynamicParams = true, the remaining 488 templates are left to on-demand rendering, and that path fails on the deployed site. Response headers confirm the split: working pages carry x-nextjs-prerender: 1 and x-nextjs-cache: HIT, while the failing ones carry no prerender header at all.

The on-demand render does start (an unknown slug such as /templates/does-not-exist still returns a correct 404 through notFound()), but rendering real template content on-demand 500s in production. Pure SSR routes such as /templates and /blog/<post> are unaffected, so this is specific to the non-prerendered ISR path.

Fix

Prerender every template, which is what the sibling blog/tag/[tag] route already does:

return templates.map((template) => ({ id: template.id }));

These pages are SEO landing pages for a catalog that changes only when the templates repo is updated, so building all of them is the intended shape. dynamicParams stays true, so a template added upstream between deploys is
still handled.

Verification

Both branches were rebuilt clean (rm -rf .next) and served with next start using the same runtime layout as Dockerfile.website (prod-pruned node_modules, only .next, public and package.json), with a cold ISR cache.

before after
prerendered template HTML files 30 518
pages returning 200 on a cold cache n/a 518 / 518
served as x-nextjs-prerender + x-nextjs-cache: HIT n/a 518 / 518

The last row is the meaningful one. On a cold cache a page rendered on demand reports MISS and carries no prerender header, so all 518 are being served from build output and none touch the failing path. Unknown slugs still return 404.

Content was checked too, not just status codes. On 38 sampled pages (35 of them currently returning 500 in production), the rendered docker-compose.yml and template.toml byte-match what templates.dokploy.com serves live, with the correct template name. 38 of 38, no mismatches.

Build cost, measured before and after on the same machine:

before after
total next build 9s 8s
static generation 79 pages in 1.65s 567 pages in 2.4s
.next size 186 MB 311 MB

Build time is unchanged within noise. The tradeoff is roughly 125 MB more build output for the 488 extra HTML and RSC payloads.

What this does not prove

I was not able to reproduce the 500 itself locally. The on-demand path renders fine both in a plain production build and in the Docker-equivalent layout, so the trigger appears to be specific to the deployed container and I could not get at it from outside.

This PR therefore fixes the problem by moving all 518 pages onto the same path that already works in production, rather than by repairing the on-demand path. The underlying weakness remains: a template added upstream between site deploys would still hit the failing path until the next rebuild. If a maintainer can pull the stack trace for GET /templates/audiobookshelf from the deployed container logs, that would pin down the real cause and could be fixed separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant