Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

trpc-navigation-plugin

ebg12232.5kMIT0.3.4TypeScript support: included

TypeScript Language Service Plugin that fixes broken 'go to definition' for tRPC when using declaration emit

typescript, language-service, typescript-plugin, trpc, navigation, go-to-definition

readme

tRPC Navigation Plugin

A TypeScript Language Service Plugin that fixes broken "go to definition" navigation for tRPC procedures when using TypeScript's declaration emit.

🚀 View Demo Repository - See the plugin in action with a T3 Turbo monorepo

Problem

When using tRPC with TypeScript's declaration emit (declaration: true), there's a TypeScript bug that completely breaks "go to definition" functionality. When you try to Cmd+Click on a tRPC procedure call like api.users.getUser.useQuery(), TypeScript only takes you to the root router definition - it can't navigate any deeper into nested routers or the actual procedure implementations.

This is caused by how TypeScript handles the complex type inference in tRPC's router chains when generating .d.ts files.

Solution

This plugin bypasses TypeScript's broken type-based navigation by using a configured router location. When you Cmd+Click on a tRPC procedure, the plugin intercepts the navigation request and takes you directly to the procedure implementation in your source code.

Features

  • Fixes Broken Navigation: Restores "go to definition" functionality that TypeScript's declaration emit breaks
  • Direct Source Navigation: Takes you to the actual implementation code, not type definitions
  • Simple Configuration: Just specify your router location - no complex setup
  • Intelligent Client Detection: Automatically detects any tRPC client variable (api, trpc, client, etc.)
  • useUtils Support: Full navigation support for useUtils() variables
  • Cross-Package Support: Works seamlessly in monorepos
  • Fast Performance: Direct navigation without complex type resolution

When You Need This Plugin

You need this plugin if:

  • Your project uses tRPC
  • You have declaration: true in your tsconfig.json (for generating .d.ts files)
  • "Go to definition" on tRPC procedures doesn't work or takes you to the wrong place

You DON'T need this plugin if:

  • You're not using TypeScript's declaration emit
  • Your "go to definition" already works correctly

Installation

⚠️ IMPORTANT: VS Code & Editor Setup

You MUST use the workspace TypeScript version, not the built-in version!

In VS Code, Cursor, or other VS Code-based editors:

  1. Open any TypeScript file in your project
  2. Click the TypeScript version number or {} in the bottom status bar
  3. Select "Select TypeScript Version..."
  4. Choose "Use Workspace Version" (NOT "Use VS Code's Version")

Without this step, the plugin will not be detected or loaded!

Setup Steps

  1. Install the plugin:

    npm install --save-dev trpc-navigation-plugin
    # or
    yarn add -D trpc-navigation-plugin
    # or
    bun add -D trpc-navigation-plugin
  2. Configure in your tsconfig.json with your router location:

    {
      "compilerOptions": {
        "plugins": [
          {
            "name": "trpc-navigation-plugin",
            "router": {
              "filePath": "./src/server/api/root.ts",
              "variableName": "appRouter"
            }
          }
        ]
      }
    }
  3. Switch to workspace TypeScript (see important note above)

  4. Restart the TypeScript server: Cmd+Shift+P → "TypeScript: Restart TS Server"

Configuration

The plugin requires you to specify where your tRPC router is defined:

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "./src/server/api/root.ts",  // Path to your router file
          "variableName": "appRouter"              // Name of your router variable
        }
      }
    ]
  }
}

Configuration Options

  • router.filePath (required): Path to the file containing your main tRPC router

    • Can be relative (resolved from project root) or absolute
    • Example: "./src/server/api/root.ts"
  • router.variableName (required): Name of your router variable in that file

    • Example: "appRouter", "router", "mainRouter"
  • patterns (optional): Customize pattern detection

    • procedureTypes: Procedure types to detect (default: ['query', 'mutation', 'subscription'])
    • routerFunctions: Router function names (default: ['router', 'createTRPCRouter', 'createRouter', 't.router'])
    • clientInitializers: Client initialization patterns (default: ['createTRPC', 'initTRPC', 'createTRPCClient'])
    • utilsMethod: Name of the utils method (default: 'useUtils')
  • fileExtensions (optional): File extensions to process

    • Default: ['.ts', '.tsx', '.js', '.jsx', '.mts', '.cts', '.mjs', '.cjs']
    • Add custom extensions if needed

Monorepo Setup

In monorepos, add the plugin to each package that uses tRPC:

// packages/api/tsconfig.json - where router is defined
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "./src/router/index.ts",
          "variableName": "appRouter"
        }
      }
    ]
  }
}

// packages/web/tsconfig.json - uses tRPC through @my/api package
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "../api/src/router/index.ts",
          "variableName": "appRouter"
        }
      }
    ]
  }
}

Optional: Enable Verbose Logging

For debugging, you can enable verbose logging:

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "./src/server/api/root.ts",
          "variableName": "appRouter"
        },
        "verbose": true  // Enable detailed logging
      }
    ]
  }
}

Advanced Configuration

Customize detection patterns for non-standard tRPC setups:

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "./src/server/api/root.ts",
          "variableName": "appRouter"
        },
        "patterns": {
          "procedureTypes": ["query", "mutation", "subscription", "action"],
          "routerFunctions": ["router", "createTRPCRouter", "myCustomRouter"],
          "clientInitializers": ["createTRPC", "initTRPC", "setupTRPC"],
          "utilsMethod": "useUtils"  // or "useContext" for older tRPC versions
        },
        "fileExtensions": [".ts", ".tsx", ".mts", ".cts"]
      }
    ]
  }
}

Automatic tRPC Client Detection

The plugin intelligently detects any tRPC client variable, regardless of naming:

// All of these work automatically:
export const api = createTRPCReact<AppRouter>();
export const trpc = createTRPCNext<AppRouter>();
export const client = createTRPCProxyClient<AppRouter>();
export const myCustomName = initTRPC.create();

// In your components:
api.users.getUser.useQuery();      // ✓ Works
trpc.users.getUser.useQuery();     // ✓ Works
client.users.getUser.query();       // ✓ Works
myCustomName.users.getUser.query(); // ✓ Works

// useUtils variables also work:
const utils = api.useUtils();
const apiCtx = trpc.useUtils();
utils.users.getUser.fetch();       // ✓ Works
apiCtx.users.getUser.invalidate();  // ✓ Works

How It Works

  1. Router Configuration: You specify where your tRPC router is defined
  2. Client Detection: The plugin detects when you click on a tRPC client call
  3. Direct Navigation: Uses the configured router location to navigate directly to procedures
  4. Path Resolution: Follows the navigation path through nested routers to find the target
  5. Contextual Navigation: Click on different parts for different results:
    • api.billing.claims - clicking "billing" goes to billing router
    • api.billing.claims - clicking "claims" goes to claims procedure/router

Troubleshooting

If navigation isn't working:

  1. Verify TypeScript Version: Make sure you're using the workspace TypeScript version! (See installation section)
  2. Check Configuration: Ensure your router config points to the correct file and variable name
  3. Verify Router Export: Make sure your router is exported or declared in the specified file
  4. Check TS Server Logs: Look for [TRPC-Nav] entries in the TypeScript Server logs
  5. Enable Verbose Logging: Add "verbose": true to see detailed debug information
  6. Restart TS Server: After configuration changes: Cmd+Shift+P → "TypeScript: Restart TS Server"

Common issues:

  • Plugin not loading: You're using VS Code's built-in TypeScript instead of workspace version
  • Wrong file path: Paths are resolved from the project root (where tsconfig.json is)
  • Wrong variable name: The variable name must match exactly (case-sensitive)
  • Router not found: Make sure the router is a top-level export or variable declaration

Technical Details

  • Uses TypeScript's Language Service API for navigation interception
  • Directly navigates to configured router location without complex type resolution
  • Works around TypeScript's navigation bug without modifying your build process
  • Compatible with tRPC v10+ and v11 that use the standard router pattern
  • Supports monorepo setups with relative or absolute paths
  • Does not interfere with TypeScript's type checking or declaration emit

changelog

TRPC Navigation Plugin Changelog

v2.0.0 - TypeScript Rewrite

Major Changes

  • Converted entire plugin from JavaScript to TypeScript
  • Modularized code into separate components:
    • logger.ts - Centralized logging functionality
    • cache.ts - Navigation cache with configurable timeout
    • ast-scanner.ts - AST scanning logic using ts-morph
    • types.ts - Shared TypeScript interfaces
  • Added proper build process using Bun
  • Added unit tests for cache functionality

Improvements

  • Better error handling and recovery
  • Type-safe implementation
  • Cleaner code organization
  • Proper source maps for debugging
  • Simplified dependency management using Bun

Technical Details

  • Uses typescript/lib/tsserverlibrary for TypeScript Language Service integration
  • Synchronous AST scanning for compatibility with Language Service
  • Build output in dist/ directory
  • Tests using Bun's built-in test runner

Configuration

The plugin is automatically enabled for all packages that extend from tooling/typescript/internal-package.json.