{"id":15319104,"url":"https://github.com/zoontek/next-type-routes","last_synced_at":"2026-06-22T05:31:25.509Z","repository":{"id":57750774,"uuid":"524987768","full_name":"zoontek/next-type-routes","owner":"zoontek","description":"An experiment to make next.js routes usage safer.","archived":false,"fork":false,"pushed_at":"2022-09-21T08:54:18.000Z","size":720,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-23T00:09:38.978Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zoontek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["zoontek"]}},"created_at":"2022-08-15T12:57:51.000Z","updated_at":"2023-08-05T21:50:43.000Z","dependencies_parsed_at":"2022-08-26T08:31:36.398Z","dependency_job_id":null,"html_url":"https://github.com/zoontek/next-type-routes","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zoontek/next-type-routes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoontek%2Fnext-type-routes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoontek%2Fnext-type-routes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoontek%2Fnext-type-routes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoontek%2Fnext-type-routes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zoontek","download_url":"https://codeload.github.com/zoontek/next-type-routes/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoontek%2Fnext-type-routes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34636427,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T09:03:44.329Z","updated_at":"2026-06-22T05:31:25.495Z","avatar_url":"https://github.com/zoontek.png","language":"TypeScript","funding_links":["https://github.com/sponsors/zoontek"],"categories":[],"sub_categories":[],"readme":"# 🔬 next-type-routes\n\n[![mit licence](https://img.shields.io/dub/l/vibe-d.svg?style=for-the-badge)](https://github.com/zoontek/next-type-routes/blob/main/LICENSE)\n[![npm version](https://img.shields.io/npm/v/next-type-routes?style=for-the-badge)](https://www.npmjs.org/package/next-type-routes)\n[![bundlephobia](https://img.shields.io/bundlephobia/minzip/next-type-routes?label=size\u0026style=for-the-badge)](https://bundlephobia.com/result?p=next-type-routes)\n\nAn experiment to make next.js routes usage safer.\u003cbr\u003e\n**Heavily inspired by my work on [@swan-io/chicane](https://github.com/swan-io/chicane)**\n\n_⚠️ Don't use this in production (yet)!_\n\n## Installation\n\n```bash\n$ yarn add next-type-routes\n# --- or ---\n$ npm install --save next-type-routes\n```\n\n## Quickstart\n\nFirst, you have to generate the typed routes functions. For that, I recommend using npm scripts:\n\n```json\n\"scripts\": {\n  \"type-routes\": \"type-routes src/routes.ts\",\n  \"dev\": \"yarn type-routes \u0026\u0026 next dev\",\n  \"build\": \"yarn type-routes \u0026\u0026 next build\",\n```\n\nWhen ran, this command parse your pages tree and generates a TS file (`src/routes.ts`) which looks like this:\n\n```ts\nimport { createTypedFns } from \"next-type-routes\";\n\nexport const {\n  createURL,\n  getApiRequestParams,\n  getServerSideParams,\n  useRouterWithSSR,\n  useRouterWithNoSSR,\n} = createTypedFns([\n  // Here will be all your project routes:\n  \"/\",\n  \"/api/auth/login\",\n  \"/api/projects/[projectId]\",\n  \"/projects\",\n  \"/projects/[projectId]\",\n  \"/users\",\n  \"/users/[userId]\",\n  \"/users/[userId]/favorites/[[...rest]]\",\n  \"/users/[userId]/repositories\",\n  \"/users/[userId]/repositories/[repositoryId]\",\n]);\n```\n\n## API\n\n### createURL\n\n```tsx\nimport Link from \"next/link\";\nimport { createURL } from \"path/to/routes\";\n\nexport default function ExamplePage() {\n  return (\n    \u003c\u003e\n      \u003ch1\u003eUsers\u003c/h1\u003e\n\n      {/* URL params are type safe! */}\n      \u003cLink href={createURL(\"/users/[userId]\", { userId: \"zoontek\" })}\u003e\n        zoontek\n      \u003c/Link\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n### useRouterWithSSR\n\n```tsx\nimport { useRouterWithSSR } from \"path/to/routes\";\n\nexport default function ExamplePage() {\n  const { params } = useRouterWithSSR(\"/users/[userId]\"); // we can use useRouterWithSSR since getServerSideProps is used\n  const { userId } = params.route; // userId type is string\n\n  return \u003ch1\u003e{userId} profile\u003c/h1\u003e;\n}\n```\n\n### useRouterWithNoSSR\n\n```tsx\nimport { useRouterWithNoSSR } from \"path/to/routes\";\n\nexport default function ExamplePage() {\n  const { params } = useRouterWithNoSSR(\"/users/[userId]\"); // we have to use useRouterWithNoSSR since getServerSideProps is not used\n  const { userId } = params.route; // userId type is string | undefined\n\n  if (userId == null) {\n    return \u003cspan\u003eLoading…\u003c/span\u003e;\n  }\n\n  return \u003ch1\u003e{userId} profile\u003c/h1\u003e;\n}\n```\n\n### getApiRequestParams\n\n```ts\nimport type { NextApiRequest, NextApiResponse } from \"next\";\nimport { getApiRequestParams } from \"path/to/routes\";\n\nexport default function handler(req: NextApiRequest, res: NextApiResponse) {\n  // we can access params in a safe way on API routes\n  const params = getApiRequestParams(\"/api/projects/[projectId]\", req);\n\n  res.status(200).json({ handler: \"project\", params });\n}\n```\n\n### getServerSideParams\n\n```ts\nimport { GetServerSideProps } from \"next\";\nimport Link from \"next/link\";\nimport { getServerSideParams } from \"path/to/routes\";\n\nexport const getServerSideProps: GetServerSideProps = async (context) =\u003e {\n  const params = getServerSideParams(\"/users/[userId]\", context);\n\n  // we can access params in a safe way on the server\n  console.log(params.route.userId);\n\n  return { props: {} };\n};\n```\n\n## Error handling\n\nWhat happen when I, let's say, use `useRouterWithSSR(\"/users/[userId]\")` in page with `/project/[projectId]` path?\u003cbr\u003e\nWell, it will throw an error 💥. That's why I **highly** recommend to create a [`500.tsx` page](https://nextjs.org/docs/advanced-features/custom-error-page#500-page) and wrap your app in an [Error Boundary](https://reactjs.org/docs/error-boundaries.html).\n\n![](https://github.com/zoontek/next-type-routes/blob/main/docs/screenshot.png?raw=true)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoontek%2Fnext-type-routes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzoontek%2Fnext-type-routes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoontek%2Fnext-type-routes/lists"}