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-typed-paths

v0.3.0

Published

A realtime typesafe Next.Js route generation tool

Readme

Next Typed Paths

npm version npm downloads bundle size license TypeScript

Type-safe Next.js App Router route builder with automatic generation from your file system.

Features

  • 🔒 Fully Type-Safe: Get autocomplete and type checking for all your routes
  • 🔄 Auto-Generated: Scans your Next.js app directory and generates routes automatically
  • 👀 Live Updates: Watch mode regenerates routes when files change
  • ⚙️ Configurable: Support for config files and CLI options
  • 📦 Zero Runtime Cost: All types are compile-time only

Installation

npm install next-typed-paths

Even though the generation happens at build time, you will still need this package at runtime since it constructs a runtime object: your route structure. Hence ensure you install without the -D flag via npm.

Quick Start

1. Generate Routes

npx next-typed-paths generate --input ./src/app/api --output ./src/generated/routes.ts

2. Use in Your Code

import { routes } from "./generated/routes";

// Type-safe route building
const userRoute = routes.api.users.$userId("123"); // "/api/users/123"
const listRoute = routes.api.users.$(); // "/api/users"

Configuration

Create a routes.config.ts file in your project root:

import type { RouteConfig } from "next-typed-paths";

const routeConfig: RouteConfig = {
  input: "./src/app/api",
  output: "./src/generated/routes.ts",
  watch: false,
  paramTypeMap: {
    type: "RouteParamTypeMap",
    from: "../types/params",
  },
};

export default routeConfig;

Then create your parameter types file:

// src/types/params.ts
export type RouteParamTypeMap = {
  userId: string;
  postId: number;
  teamId: `team_${string}`;
};

Multiple Configurations

You can export multiple configurations to generate routes for different parts of your application:

import type { RouteConfig } from "next-typed-paths";

const configs: RouteConfig[] = [
  {
    input: "./src/app/api",
    output: "./src/generated/api-routes.ts",
    routesName: "apiRoutes",
  },
  {
    input: "./src/app/(dashboard)",
    output: "./src/generated/dashboard-routes.ts",
    routesName: "dashboardRoutes",
  },
];

export default configs;

Configuration Options

  • input (string, required): The directory path to scan for route files. This should point to your Next.js API routes directory (e.g., ./src/app/api or ./src/app). You can use next-typed-paths for just your REST API backend or also for any page routes that return UI.

  • output (string, required): The file path where the generated TypeScript routes file will be written. This file will contain all your type-safe route builders.

  • watch (boolean, optional): When set to true, the generator will run in watch mode and automatically regenerate routes whenever files change in the input directory. Defaults to false.

  • basePrefix (string, optional): A prefix that will be prepended to all generated routes. Automatically computed from the input path - everything after /app/ becomes the prefix. For example:

    • input: "./app/api"basePrefix: "/api"
    • input: "./src/app/api/v2"basePrefix: "/api/v2"
    • Falls back to "/" if the path cannot be parsed

    You can manually override the automatic calculation by explicitly setting this value.

  • paramTypeMap (object, optional): Configuration for importing custom parameter types from your codebase. This allows you to define parameter types as a proper TypeScript interface with full IDE support, including complex types like unions, branded types, template literals, etc.

    • type (string): The name of the exported type/interface to import
    • from (string): The module path to import from (relative to the generated output file)
    • Example:
      paramTypeMap: {
        type: "RouteParamTypeMap",
        from: "./params"
      }
    • Any parameter not defined in your type map will default to string type.
  • routesName (string, optional): The name for the generated routes constant and type. The constant will be UPPERCASED (e.g., "routes" becomes const ROUTES), and the type will be PascalCased (e.g., type Routes). Defaults to "routes".

  • imports (string[], optional): An array of import statements to include at the top of the generated routes file. Useful if your route builders need to reference custom types or utilities. For example, ["import { z } from 'zod';", "import type { User } from './types';"]. Defaults to [].

CLI Commands

Generate Routes

npx next-typed-paths generate [options]

Options:

  • -i, --input <path>: Input directory to scan (default: "./app/api")
  • -o, --output <path>: Output file path (default: "./generated/routes.ts")
  • -w, --watch: Watch for changes and regenerate
  • -c, --config <path>: Path to config file

Watch Mode

npx next-typed-paths generate --watch

This will watch your app directory and automatically regenerate routes when files change.

Integration with Development Workflow

You can integrate the route generator into your development workflow to automatically regenerate routes alongside your dev server. For example, if you are using Nx, you can run both the Next.js dev server and the route generator in parallel:

NX project.json

{
  "name": "your-next-app",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "apps/your-next-app",
  "projectType": "application",
  "targets": {
    "dev": {
      "executor": "nx:run-commands",
      "options": {
        "commands": ["next dev", "npx next-typed-paths generate --watch"],
        "parallel": true
      }
    },
    "build": {
      "executor": "@nx/next:build",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/apps/your-next-app"
      }
    }
  }
}

By no means do you have to use Nx. You could use a more lightweight tool like concurrently, for example.

With "parallel": true, both commands run simultaneously:

  • next dev starts your Next.js development server
  • npx next-typed-paths generate --watch watches for route file changes and regenerates types

This ensures your route types stay in sync with your file system as you develop.

How It Works

The generator scans your Next.js app directory structure:

app/api/
├── users/
│   ├── route.ts              → routes.api.users.$()
│   └── [userId]/
│       └── route.ts          → routes.api.users.$userId(id)
└── posts/
    ├── route.ts              → routes.api.posts.$()
    └── [postId]/
        ├── route.ts          → routes.api.posts.$postId(id)
        └── comments/
            └── route.ts      → routes.api.posts.$postId(id).comments()

It uses the directory structure to generate in realtime a typed schema of the available routes in your Next.Js application. You are still responsible for ensuring you use the route in the correct way (i.e. correct HTTP method and query params), however, the route and path params are typed for you.

Examples

Basic Usage

import { routes } from "./generated/routes";

// Static routes
routes.api.auth.login(); // "/api/auth/login"

// Dynamic routes with typed parameters
routes.api.users.$userId("123"); // "/api/users/123"
routes.api.posts.$postId(456); // "/api/posts/456" - number type from RouteParamTypeMap

// Nested dynamic routes
routes.api.posts.$postId("456").comments(); // "/api/posts/456/comments"

// Access parent route
routes.api.users.$userId("123").$(); // "/api/users/123"

// Routes with children and self
routes.api.users.$(); // "/api/users"
routes.api.users.$userId("123"); // "/api/users/123"

Custom Parameter Types

Define strict parameter types for better type safety:

// params.ts
export interface RouteParamTypeMap {
  userId: string;
  postId: number;
  teamId: `team_${string}`; // Branded string type
  status: "active" | "inactive"; // Union type
}

// Usage - TypeScript enforces your parameter types
routes.api.teams.$teamId("team_123"); // ✅ Valid
routes.api.teams.$teamId("123"); // ❌ Type error - must start with "team_"
routes.api.posts.$postId(456); // ✅ Valid - number type
routes.api.posts.$postId("456"); // ❌ Type error - must be number

With Next.js

By no means are the following examples an indication you are pinned to using certain libraries (e.g. Axios, Tanstack Query). Rather I provide some examples within the context of some common patterns.

In Client Components

'use client';

import { useState } from "react";

import axios from "axios";

import { User } from "@/common/types";
import { routes } from '@/generated/routes';

export const UsersList = () => {
  const [users, setUsers] = useState<User[]>([]);

  useEffect(() => {
    // Type-safe API calls from the client
    axios.get(routes.api.users.$())
      .then(res => res.data)
      .then(setUsers);
  }, []);

  return <div>{/* render users */}</div>;
};

In Server Components

const UserProfile = async ({ userId }: { userId: string }) => {
  // Call your API with type-safe routes
  const { data: user } = await axios.get(routes.api.users.$userId(userId));
  return <div>{user.name}</div>;
};

For redirects

import { redirect } from "next/navigation";

const handleLogin = (userId: string) => {
  redirect(routes.api.auth.callback.$());
};

Building URLs for links

const UserLink = ({ userId }: { userId: string }) => {
  return <a href={routes.api.users.$userId(userId)}>View Profile</a>;
};

With TanStack Query

import { useQuery } from '@tanstack/react-query';

const UserProfile = ({ userId }: { userId: string }) => {
  const { data: user, isLoading } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => axios.get(routes.api.users.$userId(userId)).then(res => res.data),
  });

  if (isLoading) return <div>Loading...</div>;
  return <div>{user?.name}</div>;
};

License

MIT