> ## Documentation Index
> Fetch the complete documentation index at: https://cosmos-docs-cosmjs-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Protobuf Types

> Register custom message types in the Registry, create type-safe encode objects, and decode transactions

Every transaction message in Cosmos SDK is identified by a **type URL** (e.g. `"/cosmos.bank.v1beta1.MsgSend"`) and encoded as Protocol Buffers. The `Registry` in `@cosmjs/proto-signing` maps type URLs to their codec implementations so CosmJS can encode and decode messages.

## Adding Types to the Registry

Start from `defaultRegistryTypes`, which includes all standard Cosmos SDK message types, and add your own:

```typescript theme={"system"}
import { Registry } from "@cosmjs/proto-signing";
import { defaultRegistryTypes, SigningStargateClient, GasPrice } from "@cosmjs/stargate";

import { MsgCreatePost } from "./generated/blog/v1/tx";

const registry = new Registry(defaultRegistryTypes);
registry.register("/blog.v1.MsgCreatePost", MsgCreatePost);

const client = await SigningStargateClient.connectWithSigner(
  "https://rpc.my-chain.network",
  wallet,
  { registry, gasPrice: GasPrice.fromString("0.025utoken") },
);
```

Now `signAndBroadcast` can serialize `MsgCreatePost` messages:

```typescript theme={"system"}
const result = await client.signAndBroadcast(
  senderAddress,
  [
    {
      typeUrl: "/blog.v1.MsgCreatePost",
      value: MsgCreatePost.fromPartial({
        author: senderAddress,
        title: "Hello Cosmos",
        body: "This is my first post on-chain.",
      }),
    },
  ],
  "auto",
);
```

## Registering Multiple Types

When your module has several message types, define them as an array and spread into the registry:

```typescript theme={"system"}
import { GeneratedType, Registry } from "@cosmjs/proto-signing";
import { defaultRegistryTypes } from "@cosmjs/stargate";

import { MsgCreatePost, MsgEditPost, MsgDeletePost } from "./generated/blog/v1/tx";

const blogTypes: ReadonlyArray<[string, GeneratedType]> = [
  ["/blog.v1.MsgCreatePost", MsgCreatePost],
  ["/blog.v1.MsgEditPost", MsgEditPost],
  ["/blog.v1.MsgDeletePost", MsgDeletePost],
];

const registry = new Registry([...defaultRegistryTypes, ...blogTypes]);
```

## Supported Codec Formats

The `Registry` accepts types generated by any of these tools:

| Generator                                                    | Interface                | `fromPartial`      | Notes                                                   |
| ------------------------------------------------------------ | ------------------------ | ------------------ | ------------------------------------------------------- |
| [Telescope](https://github.com/cosmology-tech/telescope) 1.x | `TelescopeGeneratedType` | Yes                | Used by OsmoJS, Stargaze, dYdX, and others              |
| [ts-proto](https://github.com/stephenh/ts-proto) 1.x         | `TsProtoGeneratedType`   | Yes                | Used by `cosmjs-types` (CosmJS's own types)             |
| [ts-proto](https://github.com/stephenh/ts-proto) 2.x         | `TsProto2GeneratedType`  | Yes                | Uses `@bufbuild/protobuf` wire format                   |
| [protobufjs](https://github.com/protobufjs/protobuf.js)      | `PbjsGeneratedType`      | No (uses `create`) | Runtime-only type definitions, no codegen step required |

All four implement `encode` and `decode`. Types with `fromPartial` (Telescope, ts-proto) are preferred because they allow constructing messages from partial objects without specifying every field.

See the [Code Generation](/cosmjs/v0.38.x/guides/extending/code-generation) page for details on each tool.

## Type-Safe Encode Objects

For large projects, define typed encode objects that narrow the `typeUrl` to a string literal. This prevents typos and gives you autocomplete on the `value` field:

```typescript theme={"system"}
import { EncodeObject } from "@cosmjs/proto-signing";
import { MsgCreatePost } from "./generated/blog/v1/tx";

export interface MsgCreatePostEncodeObject extends EncodeObject {
  readonly typeUrl: "/blog.v1.MsgCreatePost";
  readonly value: Partial<MsgCreatePost>;
}

export function isMsgCreatePostEncodeObject(
  o: EncodeObject,
): o is MsgCreatePostEncodeObject {
  return o.typeUrl === "/blog.v1.MsgCreatePost";
}
```

Use them when constructing transactions:

```typescript theme={"system"}
const msg: MsgCreatePostEncodeObject = {
  typeUrl: "/blog.v1.MsgCreatePost",
  value: MsgCreatePost.fromPartial({
    author: senderAddress,
    title: "Type-safe message",
    body: "The compiler catches typos in typeUrl.",
  }),
};

const result = await client.signAndBroadcast(senderAddress, [msg], "auto");
```

## Decoding Transactions

The `Registry` also decodes incoming data. This is useful for parsing transactions from the blockchain or decoding responses:

```typescript theme={"system"}
import { decodeTxRaw } from "@cosmjs/proto-signing";

const tx = await client.getTx(txHash);
if (tx) {
  const decoded = decodeTxRaw(tx.tx);

  for (const msg of decoded.body.messages) {
    const decodedMsg = registry.decode(msg);
    console.info(`${msg.typeUrl}:`, decodedMsg);
  }
}
```

Without your custom types registered, `registry.decode` throws `Unregistered type url` for unknown message types. Register all types you expect to encounter before decoding.

## Next Steps

<CardGroup cols={2}>
  <Card title="Query Extensions" icon="magnifying-glass" href="/cosmjs/v0.38.x/guides/extending/query-extensions">
    Build typed query methods for your custom module.
  </Card>

  <Card title="Amino Converters" icon="arrows-rotate" href="/cosmjs/v0.38.x/guides/extending/amino-converters">
    Add Amino JSON signing support for wallets like Keplr and Leap.
  </Card>

  <Card title="Code Generation" icon="wand-magic-sparkles" href="/cosmjs/v0.38.x/guides/extending/code-generation">
    Generate TypeScript codecs from protobuf definitions automatically.
  </Card>
</CardGroup>
