{"id":13484956,"url":"https://github.com/tatethurston/nextjs-routes","last_synced_at":"2025-05-15T12:05:38.495Z","repository":{"id":37105242,"uuid":"473849262","full_name":"tatethurston/nextjs-routes","owner":"tatethurston","description":"Type safe routing for Next.js","archived":false,"fork":false,"pushed_at":"2025-03-17T01:11:20.000Z","size":13063,"stargazers_count":617,"open_issues_count":9,"forks_count":22,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-14T21:29:58.202Z","etag":null,"topics":["next","nextjs","routing","typescript"],"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/tatethurston.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-03-25T03:01:41.000Z","updated_at":"2025-05-07T12:57:46.000Z","dependencies_parsed_at":"2023-02-13T10:46:13.410Z","dependency_job_id":"67ec24af-7d4f-4e6f-98bd-d268b0d267c2","html_url":"https://github.com/tatethurston/nextjs-routes","commit_stats":{"total_commits":177,"total_committers":10,"mean_commits":17.7,"dds":"0.14689265536723162","last_synced_commit":"8231dbd921f001c7313abf948c42d645c372cb26"},"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tatethurston%2Fnextjs-routes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tatethurston%2Fnextjs-routes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tatethurston%2Fnextjs-routes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tatethurston%2Fnextjs-routes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tatethurston","download_url":"https://codeload.github.com/tatethurston/nextjs-routes/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337613,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["next","nextjs","routing","typescript"],"created_at":"2024-07-31T17:01:40.210Z","updated_at":"2025-05-15T12:05:33.479Z","avatar_url":"https://github.com/tatethurston.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","**1. Libraries**"],"sub_categories":["Others"],"readme":"# Next.js Routes\n\n\u003cblockquote\u003eType safe routing for Next.js\u003c/blockquote\u003e\n\n\u003cbr /\u003e\n\n\u003ca href=\"https://www.npmjs.com/package/nextjs-routes\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/v/nextjs-routes.svg\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/tatethurston/nextjs-routes/blob/main/LICENSE\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/l/nextjs-routes.svg\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/nextjs-routes\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/dy/nextjs-routes.svg\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/tatethurston/nextjs-routes/actions/workflows/ci.yml\"\u003e\n  \u003cimg src=\"https://github.com/tatethurston/nextjs-routes/actions/workflows/ci.yml/badge.svg\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://codecov.io/gh/tatethurston/nextjs-routes\"\u003e\n  \u003cimg src=\"https://img.shields.io/codecov/c/github/tatethurston/nextjs-routes/main.svg?style=flat-square\"\u003e\n\u003c/a\u003e\n\n\u003cbr /\u003e\n\n![nextjs-routes preview gif](./images/nextjs-routes.gif)\n\n## What is this? 🧐\n\n`nextjs-routes` generates type safe routing utilities from your `pages` and/or `app` directory.\n\n## Notice\n\nIf you are using Next.js's App Router you may not need this library. Next.js provides an [experimental option to generate typed links](https://nextjs.org/docs/app/building-your-application/configuring/typescript#statically-typed-links). Next.js's option only works for the `app` directory, and not `pages`. If you're using the `pages` directory, or if you're using the `app` directory and want to use typed objects instead of string interpolation to provide URL parameters and queries, use this library.\n\n## Highlights\n\n🦄 Zero config\n\n💨 Types only -- zero runtime (pages directory only)\n\n🛠 No more broken links\n\n🪄 Route autocompletion\n\n🔗 Supports all Next.js route types: static, dynamic, catch all and optional catch all\n\n## Installation \u0026 Usage 📦\n\n1. Add this package to your project:\n\n   ```sh\n   npm install nextjs-routes\n   # or\n   yarn add nextjs-routes\n   # or\n   pnpm add nextjs-routes\n   ```\n\n2. Update your `next.config.js`:\n\n   ```diff\n   + const nextRoutes = require(\"nextjs-routes/config\");\n   + const withRoutes = nextRoutes();\n\n   /** @type {import('next').NextConfig} */\n   const nextConfig = {\n     reactStrictMode: true,\n   };\n\n   - module.exports = nextConfig;\n   + module.exports = withRoutes(nextConfig);\n   ```\n\n3. Start or build your next project:\n\n   ```sh\n   npx next dev\n   # or\n   npx next build\n   ```\n\nThat's it! A `@types/nextjs-routes.d.ts` file will be generated the first time you start your server. Check this file into version control. `next/link` and `next/router` type definitions have been augmented to verify your application's routes. No more broken links, and you get route autocompletion 🙌.\n\nIn development, whenever your routes change, your `@types/nextjs-routes.d.ts` file will automatically update.\n\nIf you would prefer to generate the route types file outside of `next dev` or `next build` you can also invoke the cli directly: `npx nextjs-routes`.\n\n## Examples 🛠\n\n### Link\n\n`Link`'s `href` prop is now typed based on your application routes:\n\n```tsx\nimport Link from \"next/link\";\n\n\u003cLink\n  href={{\n    pathname: \"/foos/[foo]\",\n    query: { foo: \"bar\" },\n  }}\n\u003e\n  Bar\n\u003c/Link\u003e;\n```\n\nIf the route doesn't require any parameters, you can also use a path string:\n\n```tsx\n\u003cLink href=\"/foo\"\u003eFoo\u003c/Link\u003e\n```\n\n### useRouter\n\n`useRouter`'s returned router instance types for `push`, `replace` and `query` are now typed based on your application routes.\n\nIdentical to `Link`, `push` and `replace` now expect a UrlObject or path string:\n\n#### push\n\n```tsx\nimport { useRouter } from \"next/router\";\n\nconst router = useRouter();\nrouter.push({ pathname: \"/foos/[foo]\", query: { foo: \"test\" } });\n```\n\n#### replace\n\n```tsx\nimport { useRouter } from \"next/router\";\n\nconst router = useRouter();\nrouter.replace({ pathname: \"/\" });\n```\n\n#### query\n\n```tsx\nimport { useRouter } from \"next/router\";\n\n// query is typed as a union of all query parameters defined by your application's routes\nconst { query } = useRouter();\n```\n\nBy default, `query` will be typed as the union of all possible query parameters defined by your application routes. If you'd like to narrow the type to fewer routes or a single page, you can supply a type argument:\n\n```tsx\nimport { useRouter } from \"next/router\";\n\nconst router = useRouter\u003c\"/foos/[foo]\"\u003e();\n// query is now typed as `{ foo?: string | undefined }`\nrouter.query;\n```\n\nYou can further narrow the query type by checking the router's `isReady` property.\n\n```tsx\nimport { useRouter } from \"next/router\";\n\nconst router = useRouter\u003c\"/foos/[foo]\"\u003e();\n// query is typed as `{ foo?: string | undefined }`\nrouter.query;\n\nif (router.isReady) {\n  // query is typed as `{ foo: string }`\n  router.query;\n}\n```\n\nChecking `isReady` is necessary because of Next's [Automatic Static Optimization](https://nextjs.org/docs/advanced-features/automatic-static-optimization). The router's query object will be empty for pages that are Automatic Static Optimized. After hydration, Next.js will trigger an update to your application to provide the route parameters in the query object. See [Next's documentation](https://nextjs.org/docs/advanced-features/automatic-static-optimization) for more information. `isReady` will always return true for server rendered pages.\n\n### Route\n\nIf you want to use the generated `Route` type in your code, you can import it from `nextjs-routes`:\n\n```ts\nimport type { Route } from \"nextjs-routes\";\n```\n\n### Pathname\n\nIf you want a type for all possible `pathname`s you can achieve this via `Route`:\n\n```ts\nimport type { Route } from \"nextjs-routes\";\n\n// '/' | '/foos/[foo]' | 'other-route' | ...\ntype Pathname = Route[\"pathname\"];\n```\n\n### RoutedQuery\n\nIf you want to use the generated `Query` for a given `Route`, you can import it from `nextjs-routes`:\n\n```ts\n// Query | Query \u0026 { foo: string } | ...\nimport type { RoutedQuery } from \"nextjs-routes\";\n```\n\nBy default, `query` will be typed as the union of all possible query parameters defined by your application routes. If you'd like to narrow the type to fewer routes or a single page, you can supply the path as a type argument:\n\n```ts\n// Query \u0026 { foo: string }\ntype FooRouteQuery = RoutedQuery\u003c\"/foos/[foo]\"\u003e;\n```\n\n### GetServerSidePropsContext\n\nIf you're using `getServerSideProps` consider using `GetServerSidePropsContext` from nextjs-routes. This is nearly identical to `GetServerSidePropsContext` from next, but further narrows types based on nextjs-route's route data.\n\n```ts\nimport type { GetServerSidePropsContext } from \"nextjs-routes\";\n\nexport function getServerSideProps(\n  context: GetServerSidePropsContext\u003c\"/foos/[foo]\"\u003e,\n) {\n  // context.params will include `foo` as a string;\n  const { foo } = context.params;\n}\n```\n\n### GetServerSideProps\n\nIf you're using `getServerSideProps` and TypeScript 4.9 or later, you can combine the [satisfies](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator) operator with `GetServerSideProps` from nextjs-routes. This is nearly identical to `GetServerSideProps` from next, but further narrows types based on nextjs-route's route data.\n\n```ts\nimport type { GetServerSideProps } from \"nextjs-routes\";\n\nexport const getServerSideProps = (async (context) =\u003e {\n  // context.params will include `foo` as a string;\n  const { foo } = context.params;\n}) satisfies GetServerSideProps\u003c{}, \"/foos/[foo]\"\u003e;\n```\n\n## How does this work? 🤔\n\n`nextjs-routes` generates types for the `pathname` and `query` for every page in your `pages` directory. The generated types are written to `@types/nextjs-routes.d.ts` which is automatically referenced by your Next project's `tsconfig.json`. `@types/nextjs-routes.d.ts` redefines the types for `next/link` and `next/router` and applies the generated route types.\n\n## What if I need a runtime?\n\nThere are some cases where you may want to generate a type safe path from a `Route` object, such as when `fetch`ing from an API route or serving redirects from `getServerSideProps`. These accept `strings` instead of the `Route` object that `Link` and `useRouter` accept. Because these do not perform the same string interpolation for dynamic routes, runtime code is required instead of a type only solution.\n\nFor these cases, you can use `route` from `nextjs-routes`:\n\n### fetch\n\n```ts\nimport { route } from \"nextjs-routes\";\n\nfetch(route({ pathname: \"/api/foos/[foo]\", query: { foo: \"foobar\" } }));\n```\n\n### getServerSideProps\n\n```ts\nimport { route, type GetServerSidePropsContext } from \"nextjs-routes\";\n\nexport function getServerSideProps(context: GetServerSidePropsContext) {\n  return {\n    redirect: {\n      destination: route({ pathname: \"/foos/[foo]\", query: { foo: \"foobar\" } }),\n      permanent: false,\n    },\n  };\n}\n```\n\n`route` optionally accepts a `trailingSlash`:\n\n```ts\n// api/foos/foobar/\nfetch(\n  route(\n    { pathname: \"/api/foos/[foo]\", query: { foo: \"foobar\" } },\n    { trailingSlash: true },\n  ),\n);\n```\n\n### Internationalization (i18n)\n\n`nextjs-routes` refines `Link` and `useRouter` based on your [Nextjs i18n configuration](https://nextjs.org/docs/advanced-features/i18n-routing).\n\nThe following `next.config.js`:\n\n```js\nmodule.exports = withRoutes({\n  i18n: {\n    defaultLocale: \"de-DE\",\n    locales: [\"de-DE\", \"en-FR\", \"en-US\"],\n  },\n});\n```\n\nWill type `Link` and `useRouter`'s `locale` as `'de-DE' | 'en-FR' | 'en-US'`. All other i18n properties (`defaultLocale`, `domainLocales` and `locales`) are also typed.\n\nIf you want to use the generated `Locale` type, you can import it from `nextjs-routes`:\n\n```ts\nimport { Locale } from \"nextjs-routes\";\n```\n\n## Configuration\n\nYou can pass the following options to `nextRoutes` in your `next.config.js`:\n\n```js\nconst nextRoutes = require(\"nextjs-routes/config\");\nconst withRoutes = nextRoutes({\n  outDir: \"types\",\n  cwd: __dirname,\n});\n```\n\n- `outDir`: The file path indicating the output directory where the generated route types should be written to (e.g.: \"types\"). The default is to create the file in the same folder as your `next.config.js` file.\n\n- `cwd`: The path to the directory that contains your `next.config.js` file. This is only necessary for non standard project structures, such as `nx`. If you are an `nx` user getting the `Could not find a Next.js pages directory` error, use `cwd: __dirname`.\n\n## Troubleshooting\n\n### Could not find a Next.js pages directory\n\nNon standard project structures, such as those using `nx`, require that users supply a path to their `next.config.js`. For `nx`, this is because `nx` introduces wrapping layers that invoke commands differently than using the `next` cli directly.\n\nSolution:\n\n```diff\nconst nextRoutes = require(\"nextjs-routes/config\");\nconst withRoutes = nextRoutes({\n+  cwd: __dirname\n});\n```\n\n## Contributing 👫\n\nPR's and issues welcomed! For more guidance check out [CONTRIBUTING.md](https://github.com/tatethurston/nextjs-routes/blob/main/CONTRIBUTING.md)\n\nAre you interested in bringing a `nextjs-routes` like experience to another framework? [Open an issue](https://github.com/tatethurston/nextjs-routes/issues/new) and let's collaborate.\n\n## Licensing 📃\n\nSee the project's [MIT License](https://github.com/tatethurston/nextjs-routes/blob/main/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftatethurston%2Fnextjs-routes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftatethurston%2Fnextjs-routes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftatethurston%2Fnextjs-routes/lists"}