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

@creatorem/next-trpc

v1.0.14

Published

A simple typed rpc interface to easily type api endpoints in an app router nextjs application.

Downloads

1,357

Readme

next-trpc

A simple typed rpc interface to easily type api endpoints in an app router nextjs application.

Installation

npm install @creatorem/next-trpc zod

Setup

Create a router file

Contains your api endpoints.

trpc/router.ts

import { router, endpoint } from "@creatorem/next-trpc";
import z from "zod";

export const appRouter = router({
  getUser: endpoint.action(async ({ db }) => {
    return await myAsyncFunction();
  }),
  greeting: endpoint
    .input(
      // you can add zod typechecking to your entry params
      z.object({
        name: z.string(),
        age: z.coerce.number(),
      })
    )
    .action(({ name, age }) => {
      return `Hi my name is ${name}, and I am ${age} years old.`;
    }),
});

export type AppRouter = typeof appRouter;

Connect your router to an api endpoint.

app/api/trpc/[trpc]/route.ts

import { createTrpcAPI } from "@creatorem/next-trpc/server";
import { appRouter } from "~/trpc/router";

const handler = createTrpcAPI({
  router: appRouter,
});

export { handler as GET, handler as POST };

Start fetching with a type safe client!

trpc/client.ts

import { envs } from "~/envs";
import { createTrpcClient } from "@creatorem/next-trpc/client";
import { type AppRouter } from "./router";

const url = envs().NEXT_PUBLIC_YOUR_APP_URL + "/api/trpc";

export const trpc = createTrpcClient<AppRouter>({
  url,
  headers: async () => {
    // add custom headers like Authorization to make it works with auth logic
    return {
      /* Authorization: `Bearer ${jwt!}` */
    };
  },
});

Done !

Usage

Now you can use the trpc client and server side.

app/layout.tsx

import React from "react";
import { redirect } from "next/navigation";
import { trpc } from "~/trpc/client";

export default async function Layout(
  props: React.PropsWithChildren
): Promise<React.JSX.Element> {
  const user = await trpc.getUser.fetch();

  if (!user) {
    return redirect(/* path to login page */);
  }

  return <>{props.children}</>;
}

Integrated useQuery hook usage

We offer a client side only function to create client object that pre-implement the useQuery hook from @tanstack/react-query package.

You need to have @tanstack/react-query installed.

npm install @tanstack/react-query

Then you can create the following file :

trpc/query-client.ts

import "client-only";

import { envs } from "~/envs";
import { createTrpcQueryClient } from "@creatorem/next-trpc/query-client";
import { useQuery } from "@tanstack/react-query";
import { type AppRouter } from "./router";

const url = envs().NEXT_PUBLIC_YOUR_APP_URL + "/api/trpc";

export const clientTrpc = createTrpcQueryClient<AppRouter>({
  url,
  useQuery,
  headers: async () => {
    // add custom headers like Authorization to make it works with auth logic
    return {
      /* Authorization: `Bearer ${jwt!}` */
    };
  },
});

Now you can do :

"use client";

import React from "react";
import { clientTrpc } from "~/trpc/query-client";

export const MyClientComponent: React.FC<React.PropsWithChildren> = (props) => {
  const { data: user } = clientTrpc.getUser.useQuery();
  /* ... */

  return <>{props.children}</>;
};

[!WARNING] Do not forget to wrap your app with <QueryClientProvider>. See installation instructions for more details.

Use a router context

You can use a context object to pass data to all your endpoint callbacks.

trpc/router.ts

import { CtxRouter, endpoint } from "@creatorem/next-trpc";
import z from "zod";

export const createContext = async () => {
  /* your own context logic here ... */
  return { db /* let's say db is a database client. */ };
};

const ctx = new CtxRouter<Awaited<ReturnType<typeof createContext>>>();

export const appRouter = ctx.router({
  getUser: ctx.endpoint.action(async ({ db }) => {
    return await db.user.get();
  }),
  greeting: ctx.endpoint
    .input(
      // you can add zod typechecking to your entry params
      z.object({
        name: z.string(),
        age: z.coerce.number(),
      })
    )
    .action(({ name, age }) => {
      return `Hi my name is ${name}, and I am ${age} years old.`;
    }),
});

export type AppRouter = typeof appRouter;

[!NOTE] Param types are serialized during the http request to the api. You need to use z.coerce for non-string types.

Next pass your context to the nextjs api endpoint.

app/api/trpc/[trpc]/route.ts

import { createTrpcAPI } from "@creatorem/next-trpc/server";
import { appRouter, createContext } from "~/trpc/router";

const handler = createTrpcAPI({
  router: appRouter,
  ctx: createContext,
});

export { handler as GET, handler as POST };