# We deleted our only dynamic content route to get fourteen folders, and not one URL changed

> Source: <https://dev.to/daniel_pertu/we-deleted-our-only-dynamic-content-route-to-get-fourteen-folders-and-not-one-url-changed-fhm>
> Published: 2026-11-06 09:47:53+00:00

CogniPrep had five pages describing test formats, at `/tests/numerical-reasoning` and four siblings, served by one dynamic route: `app/tests/[test-type]/page.tsx` reading an entry out of a registry. That is the obvious shape, and for five pages it was fine. Last week the cluster went to fourteen pages, and the dynamic route is gone. Every URL is identical to what it was.

Git recorded the change honestly, as a rename:

``` js
.../page.tsx => components/tests/TestTypeShell.tsx | 249 ++-
```

The body of the dynamic route became a shell component, and fourteen folders now each hold an eleven-line file:

``` js
import { testTypeMetadata } from '@/components/tests/test-type-metadata';
import { TestTypeShell } from '@/components/tests/TestTypeShell';

// Content and metadata live in lib/tests/test-types.ts.
const SLUG = 'abstract-reasoning';

export const metadata = testTypeMetadata(SLUG);

export default function Page() {
  return <TestTypeShell slug={SLUG} />;
}
```

Fourteen near-identical files is the kind of thing a reviewer flags as duplication. Here is what buying them gets you.

**A page can stop sharing.** The whole point of a registry-driven cluster is that every page has the same shape, and the day one page needs a different shape, a dynamic route makes you branch inside the shell for every other page's benefit. With a folder, the odd page out stops importing the shell and keeps its URL. Nothing else in the cluster notices.

**The route is greppable.** "Where does `/tests/error-checking` come from" has a filesystem answer, which matters more than it sounds in a codebase where 56 provider hubs, 180 employer guides and 107 articles all resolve through registries.

**A missing page becomes a test failure rather than a 404 in production.** The new guard test, in full, is two assertions in both directions:

```
it('has a route folder for every registry entry', ...)
it('has a registry entry for every route folder', ...)
```

with a file comment that says why each direction matters: a registry entry with no folder 404s *while still appearing in the sitemap and the footer*, and a folder with no entry throws at build time. Under the dynamic route only the second failure was possible, so the first one was invisible until Search Console noticed.

The footer has a smaller version of the same idea. It names seven of the fourteen formats by slug and resolves each one against the registry:

```
if (!entry) throw new Error(`Footer names unknown test type ${slug}`);
```

A renamed slug now breaks the build instead of the footer.

`lib/tests/test-types.ts` went from 973 lines to 2,228. The new fields are all about the relationship between pages rather than the content of one page:

`parent`.` group`.` coverageNote`.
The fourteen pages reference 382 practice tests between them, 294 distinct out of the 372 we run. Logical reasoning alone lists 78, which is why its HTML weighs 593 KB against the 140 KB of its diagrammatic child. Thirteen of the fourteen keep `h1` and `<title>` character-for-character identical, with a comment saying why: the result snippet and the page heading should match, so nobody wonders whether they clicked the right link.

This is the part that took judgement rather than typing, and the registry's own doc comment is the policy:

A game belongs on a page only if it genuinely practises that format, judged from the game itself and its provider dossier, never from its name. Bridge Abstract is an operator test, so it sits on diagrammatic reasoning; EEI Interpreting Diagrams is map and legend reading, so it does not.

Two tests with "diagram" in the name, one on the page, one off it. Doing that consistently is how `/tests/diagrammatic-reasoning` ends up with four practice tests when a keyword-matching script would have given it fifteen.

And then the page says so, out loud, in its own FAQ: "Why does this page list only four tests?" The answer names the four vendors whose tests are genuinely diagrammatic and says we do not pad the page with tests that merely have "diagram" in the name.

Open [cogniprep.app/tests](https://cogniprep.app/tests): fourteen formats in four groups, all served from folders now. Then open [cogniprep.app/tests/logical-reasoning](https://cogniprep.app/tests/logical-reasoning) and note that the first thing under the intro is a list of its four children, not a wall of practice tests.

Then open [cogniprep.app/tests/diagrammatic-reasoning](https://cogniprep.app/tests/diagrammatic-reasoning) and read the last FAQ. A page admitting its own thin coverage is a strange thing to ship deliberately, and it is the only version of that page we could defend.

Compare the two page sources if you want the size difference: `curl -s https://cogniprep.app/tests/logical-reasoning | wc -c` against the same for the diagrammatic page.
