HomePostsgSSP and tRPC

How to use GetServerSideProps with tRPC

Date
Last Updated
Profile Picture
Peter White@petewht
Contents

GetServerSideProps (gSSP) is your ticket to a better NextJS experience. With gSSP running on the backend, you can enjoy the performance of a static site and the interactivity of a client-side rendered site.

Because gSSP runs on the backend, anything you do in your router can also be done in gSSP. Use secrets here, server logic, whatever, they'll be hidden from the client.

Three options for using gSSP with tRPC and NextJS: extract a function, use createCaller or use SSG helpers.

Extract a Function

  1. Extract the logic from that procedure in a function. This will usually take your database client and your Zod input as parameters
  2. In your GetServerSideProps, import that function and call it with the database client and the desired input
  3. Use useQuery hook in your page component. You'll need to set initialData in your useQuery to your props

Downside: not type-safe

export default function Page(props) {
  const { data } = trpc.posts.getOne.useQuery(
    { id: props.id },
    { initialData: props.post },
  );
  return <div>{data.title}</div>;
}
 
export const getServerSideProps = async (ctx) => {
  const post = await getPost({ prisma, input: { id: ctx.params.id } });
  return {
    props: {
      id,
      post,
    },
  };
};

Use createCaller

A type-safe way to work with gSSP and tRPC is to use the createCaller function.

  1. Export your tRPC router
  2. Import your router in your GetServerSideProps, then create a caller
  3. Use your caller to call the procedure you want
  4. Return the result
export const getServerSideProps = async (ctx) => {
  // const context = await createContext(ctx) might be required depending on your setup
  const trpc = appRouter.createCaller(ctx);
  const result = await trpc.greeting({ name: 'peter' });
 
  return {
    props: {
      greeting: result,
    },
  };
};

SSG Helpers

A type-safe, simpler way to work with gSSP and tRPC is to use the SSG helpers.

  1. Use createServerSideHelpers (prior to v10.19.0, use createProxySSGHelpers), passing the router, context and your transformer to it
  2. Use prefetch the call the procedures you want. You don't need to assign these to a variable
  3. Pass ssg.dehydrate() to the gSSP props.

Result: server-side content magically re-hydrated (thanks to Tanstack), type-safe.

export default function Page(props) {
  const { data } = trpc.posts.getOne.useQuery({ id: props.id });
  return <div>{data.title}</div>;
}
 
export const getServerSideProps = async (ctx) => {
  const ssg = createServerSideHelpers({
    router: appRouter,
    ctx: await createContext(context) // replace with your own context,
    transformer: superjson,
  });
 
  await ssg.prefetch('posts.getOne', { id: ctx.params.id });
 
  return {
    props: {
      trpcState: ssg.dehydrate(),
      id,
    },
  };
};

Note that prefetch does not return a result, and never throws an error. You can use fetch instead if you need this - for example, to transform the output or do something else with it.


Thanks for Reading!

I always appreciate feedback or suggestions for future blog posts. You can find me on Twitter or if you want to improve the article to help future readers, please feel free to submit a PR.

🦉 2794 days

Duolingo Streak

Proudly created in beautiful Sætre in Norway 🇳🇴