npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

next-typesafe-path

v0.0.5

Published

Type-safe path for Next.js

Readme

next-typesafe-path

A library for type-safe routing in Next.js.

Features

  • Type-safe routing for Next.js
  • Support for dynamic routes ([id]), catch-all routes ([...slug]), and optional catch-all routes ([[...slug]])
  • Type-safe handling of search parameters (query parameters)
  • Define globally available search parameters
  • Compatible with both App Router and Pages Router

Acknowledgments

This project is inspired by:

Installation

npm install next-typesafe-path --save-dev
# or
yarn add next-typesafe-path --dev
# or
pnpm add next-typesafe-path --save-dev
# or
npx next-typesafe-path

Usage

1. Generate Type Definitions

Run the following command to generate type definitions:

npx next-typesafe-path

Add the CLI to your package.json scripts:

{
  "scripts": {
    "dev": "npm run dev:path & npm run dev:next",
    "dev:path": "next-typesafe-path --watch",
    "dev:next": "next dev",
    "build": "next-typesafe-path && next build"
  }
}

generate a _next-typesafe-path.d.ts file in the root of your project.

Options

  • --config-dir: Specify the configuration file directory (default: project root)
  • --trailing-slash: Add trailing slashes to URLs (default: false)
  • --watch: Watch for file changes and regenerate type definitions automatically

2. Set Up Global Search Parameters (Optional)

Create a next-typesafe-path.config.ts file in the root of your project to define globally available search parameters:

// next-typesafe-path.config.ts
import { createSearchParams, InferSearchParams, setGlobalSearchParams } from "next-typesafe-path";

export const searchParams = createSearchParams((p) => ({
  // Define your global search parameters here
  locale: p.enumOr(["en", "ja"], "ja").optional(),
}));

export type SearchParams = InferSearchParams<typeof searchParams>;

// Set global configuration
setGlobalSearchParams(searchParams);

Next, import this configuration file in your layout.tsx (for App Router) or _app.tsx (for Pages Router):

// app/layout.tsx (App Router)
import "../next-typesafe-path.config";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>{children}</body>
    </html>
  );
}
// pages/_app.tsx (Pages Router)
import "../next-typesafe-path.config";
import type { AppProps } from "next/app";

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

3. Use Routing

Generate Paths

Use the $path function to generate type-safe paths:

import { $path } from "next-typesafe-path";

// Regular path
const path1 = $path("/about");

// Dynamic route
const path2 = $path("/users/[id]", { id: "123" });

// Path with search parameters
const path3 = $path("/blog", { page: 1, sort: "desc" });

// Dynamic route + search parameters
const path4 = $path("/users/[id]", { id: "123" }, { tab: "profile" });

// Catch-all route
const path5 = $path("/shop/[...categories]", { categories: ["men", "shoes"] });

// Optional catch-all route
const path6 = $path("/products/[[...filters]]", { filters: ["sort", "price"] });

// Optional catch-all route without path param
const path7 = $path("/products/");

Define and Use Search Parameters

Define search parameters in your page component and use them in a type-safe way:

// app/blog/page.tsx (App Router)
import { createSearchParams, InferSearchParams, parseSearchParams } from "next-typesafe-path";

// Define search parameters
const SearchParams = createSearchParams((p) => ({
  page: p.numberOr(1),
  sort: p.enumOr(["asc", "desc"] as const, "asc"),
  q: p.stringOr(""),
}));

// Extract type
export type SearchParams = InferSearchParams<typeof SearchParams>;

// Page component
export default async function BlogPage({
  searchParams,
}: {
  searchParams: Promise<SearchParams>;
}) {
  // Parse search parameters
  const params = parseSearchParams(SearchParams, await searchParams);

  return (
    <div>
      <h1>Blog</h1>
      <p>Page: {params.page}</p>
      <p>Sort: {params.sort}</p>
      <p>Query: {params.q}</p>
      {/* Access global search parameters */}
      <p>Locale: {params.locale}</p>
    </div>
  );
}
// pages/blog.tsx (Pages Router)
import { createSearchParams, InferSearchParams, parseSearchParams } from "next-typesafe-path";
import { GetServerSideProps } from "next";

// Define search parameters
const SearchParams = createSearchParams((p) => ({
  page: p.numberOr(1),
  sort: p.enumOr(["asc", "desc"] as const, "asc"),
  q: p.stringOr(""),
}));

// Extract type
export type SearchParams = InferSearchParams<typeof SearchParams>;

// Page component
export default function BlogPage({ params }: { params: SearchParams }) {
  return (
    <div>
      <h1>Blog</h1>
      <p>Page: {params.page}</p>
      <p>Sort: {params.sort}</p>
      <p>Query: {params.q}</p>
      {/* Access global search parameters */}
      <p>Locale: {params.locale}</p>
    </div>
  );
}

// Parse search parameters on the server side
export const getServerSideProps: GetServerSideProps = async ({ query }) => {
  const params = parseSearchParams(SearchParams, query);
  return { props: { params } };
};

Advanced Usage

Customize Parameter Builder

Use the createSearchParams function to create your own parameter builder:

import { createSearchParams, InferSearchParams } from "next-typesafe-path";

// Custom parameter builder
const SearchParams = createSearchParams((p) => ({
  // Required parameter
  id: p.string(),
  // Parameter with default value
  page: p.numberOr(1),
  // Enum parameter
  sort: p.enumOr(["asc", "desc"] as const, "asc"),
  // Optional parameter
  q: p.string().optional(),
  // Array parameter
  tags: p.array(p.string()).optional(),
}));

// or

const SearchParams = createSearchParams(() => ({
  id: z.string(),
  page: z.number(),
}));

// Extract type
export type SearchParams = InferSearchParams<typeof SearchParams>;

License

MIT