---
title: Renaming Types
llmstxt: true
---

import { ClientTabs, ClientTabItem } from "@components/client-tabs";

This page documents how to customize the name of models, operations, and parameters. For an overview of the setup, please visit the setup page.

:::note
The TypeSpec compiler provides an `@encodedName` decorator that allows changing the name of the property for a given serialization format.
However in Azure we recommend that you define the property name as the value sent on the wire and use the `@clientName` decorator to change the name of the generated property.
:::

## Default behaviors

By default, any language code generator will assume the TYPESPEC name is the client. For clarity, generators do not attempt to do any auto-magic rename.

> **NOTE:** While names are not transformed, they will be adapted to what is idiomatic of the language (Python snake_case, etc.).

<ClientTabs>

```typespec title=main.tsp
namespace PetStoreNamespace;

/** This is the input I need */
@resource("input")
model InputModel {
  /** Id of this object */
  @key
  @visibility(Lifecycle.Read)
  name: string;
}

/** Read my resource */
op get is ResourceRead<InputModel>;
```

```python
class InputModel:
  name: str = rest_field(readonly=True)

response: InputModel = client.get(name="name")
```

```csharp
namespace PetStoreNamespace.Models
{
  public partial class InputModel
  {
    public string Name { get; }
  }
}

namespace PetStoreNamespace
{
  public partial class PetStoreNamespaceClient
  {
    // protocol method
    public virtual async Task<Response> GetAsync(string name, RequestContext context) {}
    public virtual Response Get(string name, RequestContext context) {}
    // convenience method
    public virtual async Task<Response<InputModel>> GetAsync(string name, CancellationToken cancellationToken = default) {}
    public virtual Response<InputModel> Get(string name, CancellationToken cancellationToken = default) {}
  }
}
```

```typescript
export interface InputModel {
  readonly name: string;
}

export async function get(
  context: Client,
  name: string,
  options: GetOptionalParams = { requestOptions: {} }
): Promise<InputModel>；
```

```java
package petstorenamespace.models;
public final class InputModel {
    public String getName()
}

package petstorenamespace;
public final class PetStoreNamespaceClient {
    public Response<BinaryData> getWithResponse(String name, RequestOptions requestOptions)
    public InputModel get(String name)
}
```

```go
type InputModel struct {
	Name string
}

type PetStoreNamespaceClientGetResponse struct {
	InputModel
}

type PetStoreNamespaceClient struct {}

func NewPetStoreNamespaceClient() *PetStoreNamespaceClient {
  return &PetStoreNamespaceClient{}
}

func (client *PetStoreNamespaceClient) Get(ctx context.Context, name string, options *PetStoreNamespaceClientGetOptions) (PetStoreNamespaceClientGetResponse, error)
```

</ClientTabs>

## Customizations

### Renaming models and attributes

You can rename models and attributes. [Renames have a target](https://microsoft.github.io/typespec/standard-library/projected-names#known-targets):

- `client` means that all client will use that name
- `csharp`, `javascript`, `python`, `java` means you target this specific language

Language target takes priority over `client` target.

> **NOTE:** As model name do not get serialized as JSON, sometimes the best choice is to rename the main TYPESPEC for clarity. Talk to your emitter contact is you're unsure
> if you should rename the model in the main TYPESPEC or customize it.

<ClientTabs>

```typespec title=client.tsp
import "./main.tsp";
import "@azure-tools/typespec-client-generator-core";

using Azure.ClientGenerator.Core;

@@clientName(InputModel, "InputOptions"); // Use InputOptions as a base name in clients
@@clientName(InputModel, "ParameterOptions", "csharp"); // Prefer a different name for C# only

@@clientName(InputModel.name, "input_name", "python"); // Python may need a different to be idiomatic
```

```python
class InputOptions:
  input_name: str = rest_field(rest_name="name", readonly=True)

response: InputOptions = client.get(input_name="name")
```

```csharp
namespace PetStoreNamespace.Models
{
  public partial class ParameterOptions
  {
    public string Name { get; }
  }
}

namespace PetStoreNamespace
{
  public partial class PetStoreNamespaceClient
  {
    // protocol method
    public virtual async Task<Response> GetAsync(string name, RequestContext context) {}
    public virtual Response Get(string name, RequestContext context) {}
    // convenience method
    public virtual async Task<Response<ParameterOptions>> GetAsync(string name, CancellationToken cancellationToken = default) {}
    public virtual Response<ParameterOptions> Get(string name, CancellationToken cancellationToken = default) {}
  }
}
```

```typescript
// Typescript do not change behavior based on protocolAPI or convenientAPI
```

```java
package petstorenamespace.models;
public final class InputOptions {
    public String getName()
}

package petstorenamespace;
public final class PetStoreNamespaceClient {
    public Response<BinaryData> getWithResponse(String name, RequestOptions requestOptions)
    public InputOptions get(String name)
}
```

```go
type InputOptions struct {
	Name string
}

type PetStoreNamespaceClientGetResponse struct {
	InputOptions
}

type PetStoreNamespaceClient struct {}

func NewPetStoreNamespaceClient() *PetStoreNamespaceClient {
  return &PetStoreNamespaceClient{}
}

func (client *PetStoreNamespaceClient) Get(ctx context.Context, name string, options *PetStoreNamespaceClientGetOptions) (PetStoreNamespaceClientGetResponse, error)

```

</ClientTabs>

### Renaming operations and parameters

#### Renaming operations

You can rename operations using the `@clientName` decorator:

<ClientTabs>

```typespec title=client.tsp
import "./main.tsp";
import "@azure-tools/typespec-client-generator-core";

using Azure.ClientGenerator.Core;

@@clientName(Get, "Read"); // Use InputOptions as a base name in clients
@@clientName(Get, "GetComputed", "python"); // Note that Python will still snake_case it
```

```python
class InputModel:
  name: str = rest_field(readonly=True)
response: InputModel = client.get_computed(name="name")
```

```csharp
namespace PetStoreNamespace.Models
{
  public partial class InputModel
  {
    public string Name { get; }
  }
}

namespace PetStoreNamespace
{
  public partial class PetStoreNamespaceClient
  {
    // protocol method
    public virtual async Task<Response> ReadModelAsync(string name, RequestContext context) {}
    public virtual Response ReadModel(string name, RequestContext context) {}
    // convenience method
    public virtual async Task<Response<InputModel>> ReadModelAsync(string name, CancellationToken cancellationToken = default) {}
    public virtual Response<InputModel> ReadModel(string name, CancellationToken cancellationToken = default) {}
  }
}
```

```typescript
// Typescript do not change behavior based on protocolAPI or convenientAPI
```

```java
package petstorenamespace.models;
public final class InputModel {
    public String getName()
}

package petstorenamespace;
public final class PetStoreNamespaceClient {
    public Response<BinaryData> readModelWithResponse(String name, RequestOptions requestOptions)
    public InputModel readModel(String name)
}
```

```go
type InputModel struct {
	Name string
}

type PetStoreNamespaceClient struct {}

func NewPetStoreNamespaceClient() *PetStoreNamespaceClient {
  return &PetStoreNamespaceClient{}
}

type PetStoreNamespaceClientReadResponse struct {
	InputModel
}

func (client *PetStoreNamespaceClient) Read(ctx context.Context, name string, options *PetStoreNamespaceClientReadOptions) (PetStoreNamespaceClientReadResponse, error)

```

</ClientTabs>

#### Renaming operation parameters

Operation parameters can be renamed using the `@clientName` decorator applied from the `client.tsp` file using the `@@` augment syntax. This is useful when you want different parameter names in the generated client SDK while keeping the wire name unchanged.

:::note
The name of an operation parameter is **not** part of the API definition for most parameter types. For query parameters, the wire name is controlled by the `@query` decorator (or the parameter name if `@query` has no arguments). Changing a parameter name is an **SDK breaking change** but not an API breaking change.
:::

To rename operation parameters, apply the `@clientName` decorator from a separate `client.tsp` file:

<ClientTabs>

```typespec title=main.tsp
namespace PetStoreNamespace;

/** This is the input I need */
@resource("input")
model InputModel {
  /** Id of this object */
  @key
  @visibility(Lifecycle.Read)
  name: string;
}

/** Read my resource */
op get(name: string, @query filter?: string): InputModel;
```

```typespec title=client.tsp
import "./main.tsp";
import "@azure-tools/typespec-client-generator-core";

using Azure.ClientGenerator.Core;
using PetStoreNamespace;

// Apply @clientName to the 'name' parameter of the 'get' operation
@@clientName(get::parameters.name, "resourceId");

// Apply language-specific names
@@clientName(get::parameters.filter, "search_filter", "python");
```

```python
# Generated client code
class PetStoreNamespaceClient:
  def get(self, resource_id: str, *, search_filter: Optional[str] = None, **kwargs) -> InputModel:
    """Get operation with renamed parameters.

    :param resource_id: The resource identifier (wire name: 'name')
    :param search_filter: Filter query (wire name: 'filter')
    :return: InputModel
    """
    ...

# Usage
response: InputModel = client.get(resource_id="name", search_filter="active")
```

```csharp
// Generated client code
namespace PetStoreNamespace
{
  public partial class PetStoreNamespaceClient
  {
    // protocol method
    public virtual async Task<Response> GetAsync(string resourceId, string filter, RequestContext context) {}
    public virtual Response Get(string resourceId, string filter, RequestContext context) {}
    // convenience method
    public virtual async Task<Response<InputModel>> GetAsync(string resourceId, string filter, CancellationToken cancellationToken = default) {}
    public virtual Response<InputModel> Get(string resourceId, string filter, CancellationToken cancellationToken = default) {}
  }
}

// Usage
InputModel model = await client.GetAsync(resourceId: "name", filter: "active");
```

```typescript
// Generated client code
export interface GetOptionalParams extends OperationOptions {
  filter?: string;
}

export async function get(
  context: Client,
  resourceId: string,
  options: GetOptionalParams = { requestOptions: {} },
): Promise<InputModel>;

// Usage
const result = await get(context, "name", { filter: "active" });
```

```java
// Generated client code
package petstorenamespace;
public final class PetStoreNamespaceClient {
    public Response<BinaryData> getWithResponse(BinaryData getRequest, RequestOptions requestOptions) {
      // implementation
    }

    public InputModel get(String resourceId, String filter) {
      // implementation
    }
}

// Usage
InputModel model = client.get("name", "active");
```

```go
// Generated client code
type PetStoreNamespaceClient struct {}

func NewPetStoreNamespaceClient() *PetStoreNamespaceClient {
  return &PetStoreNamespaceClient{}
}

type PetStoreNamespaceClientGetOptions struct {
  Filter *string
}

func (client *PetStoreNamespaceClient) Get(ctx context.Context, resourceID string, options *PetStoreNamespaceClientGetOptions) (PetStoreNamespaceClientGetResponse, error) {
  // implementation
}

// Usage
client := NewPetStoreNamespaceClient()
filter := "active"
resp, err := client.Get(context.TODO(), "name", &PetStoreNamespaceClientGetOptions{
  Filter: &filter,
})
```

</ClientTabs>

### Preserving exact casing

By default, language emitters adapt names to idiomatic casing conventions (e.g., `snake_case` for Python, `PascalCase` for C#). `@clientName` also allows emitters to apply language-specific casing transformations to the provided name. To prevent this and preserve the name exactly as specified, wrap it with the `exact()` function.

The `exact()` function marks a client name so that the TCGC type graph sets `isExactName: true` on the corresponding type or property. Language emitters that check this flag will preserve the name exactly as specified, without any automatic casing conversion.

`exact()` supports language scoping, so you can preserve exact casing for a specific language while letting others apply their own conventions.

<ClientTabs>

```typespec title=main.tsp
@service
namespace ExactNameService;

model ScopedModel {
  name: string;
}

@route("/property")
@post
op sendProperty(@body body: ScopedModel): ScopedModel;
```

```typespec title=client.tsp
import "./main.tsp";
import "@azure-tools/typespec-client-generator-core";

using Azure.ClientGenerator.Core;

// Scoped renames: per-language exact names with underscore prefix to verify
// that language naming logic does not strip or recase the name
#suppress "experimental-feature" "exact"
@@clientName(ExactNameService.ScopedModel.name, exact("_my_name"), "python");
@@clientName(ExactNameService.ScopedModel.name, exact("_myName"), "java");
@@clientName(ExactNameService.ScopedModel.name, exact("_MyName"), "csharp");
@@clientName(ExactNameService.ScopedModel.name, exact("_myName"), "javascript");
@@clientName(ExactNameService.ScopedModel.name, exact("_MyName"), "go");
```

```python
# not supported
```

```csharp
// not supported
```

```typescript
// not supported
```

```java
// not supported
```

```go
// not supported
```

</ClientTabs>

In this example, the scoped renames on `ScopedModel.name` use an underscore-prefixed name per language to verify that each emitter preserves the name as-is, without stripping or re-casing it. Language emitter support for `isExactName` is not yet available.

## Implementation

### Order of Operations

For consistency when generating code, the order in which overrides are applied is important. Code emitters should apply overrides in the following order.

#### Over-the-Wire JSON Names

For determining the final name of a TypeSpec entity when sent over-the-wire in JSON:

1. If the `@encodedName` decorator exists, use this value
2. Use the original name in the spec

#### Client SDK Names

For determining the final name of a TypeSpec entity when used in a client SDK (e.g. Python):

1. Check if there's a scoped `@clientName` decorator for your emitter
2. Check if there's a `@clientName` decorator at all
3. Check the friendly name
4. Use the original name in the spec

**Note: If the object name is from `@clientName` decorator, do not apply your language's casing rules on it. If it's not, apply your language's heuristics (i.e. for Python, apply snake casing)**
