Skip to content

Global config options #95

Open
Open

Description

@jonastemplestein

It would be really nice to configure some global config options - perhaps like this

const cli = createCli({
  router,
  globalOpts: z.object(...)
});

This would be stuff like global log levels etc

I'd want the global opts to be listed at the bottom of --help for any command. I'm just not sure what a nice API to process the parsed global options would be. Perhaps just merge them in the trpc root context?

Activity

  1. mmkal commented on May 29, 2025

    @mmkal
    Owner

    I briefly played with something like this, but didn't go through at the time because I was aiming to keep this library's docs as close to "just use trpc" as possible. To achieve something like this you can already use multiple .input(...)s.

    That way, the loglevel value, to use your example, is available to middleware and the procedure implementation too, instead of it being a trpc-cli only thing. It's not a "global" option per se but you can easily add the options to every procedures.

    Am on mobile so this formatting will be bad but basically:

    const t = trpcServer.initTRPC().create()
    
    export const procedure = t.procedure
      .input(z.object({
        logLevel: z.string()
      }))
      .use(({input, next}) => {
        // set log level via AsyncLocalStorage or similar
        return myLogContext.run(input.level, () => {
          return next()
        })
      })
    
    const foo = procedure
      .input(z.object({ abc: z.string() })
      .mutation(...)
    
    const bar = procedure
      .input(z.object({ def: z.string() })
      .mutation(...)
    
    const router = t.router({foo, bar})
    
    createCli({router}).run()

    I'll have to search for where trpc recommends to use this pattern for things like authed procedures etc., it might be deep in the issues.

    I think that can cover a similar use case right?


    Edit: if you don't want to use AsyncLocalStorage you could use other trpc-native features like injecting a logger into the context:

    const t = trpcServer.initTRPC().create()
    
    export const procedure = t.procedure
      .input(z.object({
        logLevel: z.string().default('info')
      }))
      .use(({input, next}) => {
        const logger = new Logger(input.logLevel)
        return next({ctx: {logger}})
      })
    
    const foo = procedure
      .input(z.object({ abc: z.string() })
      .mutation(({input, ctx}) => {
        ctx.logger.warn(`abc is ${input.abc} and log level is ${input.logLevel}`)
      })
    
    const bar = procedure
      .input(z.object({ def: z.string() })
      .mutation(...)
    
    const router = t.router({foo, bar})
    
    createCli({router}).run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions