{"id":15876,"library":"twirp-ts","title":"Twirp-TS","description":"Twirp-TS is a comprehensive TypeScript implementation of the Twirp RPC specification (v7 and v8), designed for generating both server and client code from Protocol Buffer definitions. It operates as a plugin for `protoc`, relying on either `@protobuf-ts/plugin` or `ts-proto` for the underlying protobuf message generation. The library facilitates building performant, type-safe APIs with minimal boilerplate, offering features like automatic OpenAPI V3 spec generation, server-side hooks and interceptors, and a gateway for proxying requests. It is actively maintained, with the current stable version being 2.5.0, and receives regular updates to fix bugs and introduce new generation options, such as granular client/server-only code generation. Its primary differentiator lies in providing a full-stack TypeScript solution for Twirp, ensuring strong type consistency from schema to implementation.","status":"active","version":"2.5.0","language":"javascript","source_language":"en","source_url":"https://github.com/hopin-team/twirp-ts","tags":["javascript","Twirp","Typescript"],"install":[{"cmd":"npm install twirp-ts","lang":"bash","label":"npm"},{"cmd":"yarn add twirp-ts","lang":"bash","label":"yarn"},{"cmd":"pnpm add twirp-ts","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required peer dependency for generating protobuf message definitions; alternative to ts-proto.","package":"@protobuf-ts/plugin","optional":true},{"reason":"Required peer dependency for generating protobuf message definitions; alternative to @protobuf-ts/plugin.","package":"ts-proto","optional":true},{"reason":"External tool (Protocol Buffer Compiler) essential for code generation, as twirp-ts is a protoc plugin. Can be replaced by 'buf'.","package":"protoc","optional":false},{"reason":"External tool (Buffer CLI) alternative to 'protoc' for code generation.","package":"buf","optional":true}],"imports":[{"note":"This is a dynamically generated export based on your .proto service definition. The exact name and path will vary. ESM-only imports are typical for generated TypeScript code.","wrong":"const createHaberdasherServer = require('./generated/haberdasher.twirp');","symbol":"create[ServiceName]Server","correct":"import { createHaberdasherServer } from './generated/haberdasher.twirp';"},{"note":"TwirpContext is a named export, not a default export. It provides access to request metadata and context within server handlers.","wrong":"import TwirpContext from 'twirp-ts';","symbol":"TwirpContext","correct":"import { TwirpContext } from 'twirp-ts';"},{"note":"These are named exports from the root package. Avoid importing from internal paths like `dist/errors` as they are not part of the stable public API.","wrong":"import { TwirpError } from 'twirp-ts/dist/errors';","symbol":"TwirpError, TwirpErrorCode","correct":"import { TwirpError, TwirpErrorCode } from 'twirp-ts';"}],"quickstart":{"code":"import * as http from \"http\";\nimport { TwirpContext, TwirpError, TwirpErrorCode } from \"twirp-ts\";\n// Assuming these are generated from your .proto file, e.g., 'haberdasher.proto'\nimport { createHaberdasherServer } from \"./generated/haberdasher.twirp\";\nimport { Hat, Size, Haberdasher } from \"./generated/service\";\n\n// Implement the Haberdasher service according to the generated interface\nconst haberdasherService: Haberdasher = {\n  async makeHat(ctx: TwirpContext, size: Size): Promise<Hat> {\n    // Validate input\n    if (size.inches <= 0) {\n      throw new TwirpError(TwirpErrorCode.InvalidArgument, \"size.inches must be positive\");\n    }\n\n    console.log(`Received request for hat of size: ${size.inches} inches`);\n    // Simulate work and return a hat\n    return {\n      inches: size.inches,\n      color: \"blue\",\n      name: \"fedora\"\n    };\n  }\n};\n\n// Create the Twirp server instance\nconst twirpServer = createHaberdasherServer(haberdasherService);\n\n// Create a standard Node.js HTTP server and mount the Twirp handler\nconst server = http.createServer(twirpServer.httpHandler());\n\nconst PORT = process.env.PORT || 8080;\nserver.listen(PORT, () => {\n  console.log(`Twirp Haberdasher server listening on port ${PORT}`);\n  console.log(\"To test: curl -d '{\\\"inches\\\":12}' -H \\\"Content-Type: application/json\\\" http://localhost:8080/twirp/haberdasher.Haberdasher/MakeHat\");\n});","lang":"typescript","description":"This quickstart demonstrates how to set up a basic Twirp server using Express, implementing a `Haberdasher` service with a `MakeHat` method. It shows error handling and listening on a specified port."},"warnings":[{"fix":"Refer to the 'Migrate to V2' section in the official README on GitHub for detailed instructions and necessary code updates when upgrading from v1.x.","message":"Version 2.0.0 introduced significant breaking changes, including the new Gateway feature, modifications to how peer dependencies are handled during transpilation, and changes to the custom context API. Direct migration from v1.x will require code adjustments.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Install `protoc` (e.g., `brew install protobuf` on macOS, `apt-get install protobuf` on Linux) or `buf` according to their respective documentation before attempting code generation.","message":"Twirp-TS is a `protoc` plugin and requires the Protocol Buffer Compiler (`protoc`) or Buffer CLI (`buf`) to be installed and available in your system's PATH for code generation to function correctly. This is not an npm dependency.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure your `protoc` command includes the appropriate plugin (e.g., `--plugin=protoc-gen-ts` for `@protobuf-ts/plugin` or `--plugin=protoc-gen-ts_proto` for `ts-proto`) and corresponding output options, in addition to the `twirp_ts` plugin.","message":"Users must explicitly choose and configure either `@protobuf-ts/plugin` or `ts-proto` to generate the base protobuf message definitions. `twirp-ts` only generates the service stubs, not the data types themselves.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Utilize `--twirp_ts_opt=client_only` or `--twirp_ts_opt=server_only` in your `protoc` command to control the generated output and potentially reduce build artifact size for specific contexts.","message":"Beginning with v2.3.0, `twirp-ts` introduced granular code generation options (`standalone`, `client_only`, `server_only`) via `--twirp_ts_opt`. Not specifying an option will generate both client and server code, which might be undesired in monorepos or specific build pipelines.","severity":"gotcha","affected_versions":">=2.3.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Ensure `node_modules/.bin` is in your PATH or provide the full path to the plugin using `--plugin=protoc-gen-twirp_ts=./node_modules/.bin/protoc-gen-twirp_ts` in your `protoc` command.","cause":"The `protoc` command cannot find the `protoc-gen-twirp_ts` executable, often due to it not being in PATH or an incorrect `--plugin` flag path.","error":"protoc-gen-twirp_ts: program not found"},{"fix":"Run your `protoc` command with `twirp-ts` (and `protobuf-ts` or `ts-proto`) to generate the files. Verify the `OUT_DIR` matches your TypeScript configuration's `include` or `paths` settings.","cause":"The protobuf message or Twirp service code has not been generated, the output directory is incorrect, or TypeScript isn't configured to include the generated files.","error":"Cannot find module './generated/service' or its corresponding type declarations."},{"fix":"Ensure the service implementation passed to `create[Service]Server` fully satisfies the generated TypeScript interface, and that all necessary generated files are imported and used correctly at runtime.","cause":"The Twirp server or client object was not correctly initialized, often due to an incorrect service implementation or a mismatch between generated code and runtime usage.","error":"TypeError: Cannot read properties of undefined (reading 'httpHandler')"}],"ecosystem":"npm"}