> This page is for SDKs, version Legacy.
> For other versions, use one of these documentation indexes:
> - Current (default): https://buildwithfern.com/learn/sdks/current/llms.txt
> - Legacy: https://buildwithfern.com/learn/sdks/legacy/llms.txt

> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt.

# Server URL templating

> Configure server URL templating in Fern SDKs to support dynamic base URLs with variables like region and environment.

> **You're viewing the legacy SDK docs**
>
> These pages cover SDK generation configured with `generators.yml`. New projects use `sdk-config.yml`, so see [the Current version of this page](/learn/sdks/deep-dives/server-url-templating) for up-to-date guidance. To move an existing project, follow the [SDK Config migration guide](/learn/sdks/legacy/generators/migration-guides/sdk-config), which walks through `fern sdk migrate`, and review the [`sdk-config.yml` reference](/learn/sdks/reference/sdk-config).

Server URL templating lets you define base URLs with variable placeholders (e.g., `{region}`, `{environment}`) that SDK users can customize at runtime. This is useful for APIs deployed across multiple regions, environments, or custom domains.

Server URL templating is supported for TypeScript, Python, Java, Go, C#, PHP, and Ruby SDK generation.

## Generated SDK behavior

Fern generates an environments module that exposes the default URLs for each named server. SDK users can select a pre-defined environment, set URL variables through client options, or pass custom URL strings. Variable names that conflict with existing client options use a `serverUrl` prefix in the language's casing convention, such as `serverUrlEnvironment`.

#### TypeScript

The generated SDK exposes an `Environment` object:

**`environments.ts`**

```typescript title="environments.ts"
export const MyApiEnvironment = {
    RegionalApiServer: {
        base: "https://api.example.com/v1",
        auth: "https://auth.example.com",
    },
} as const;
```

SDK users can select an environment, set URL variables, or pass a custom base URL when constructing the client:

```typescript
import { MyApiClient } from "my-api";

// Use the default environment
// → https://api.example.com/v1
const client = new MyApiClient();

// Target a specific region and environment via URL variables
// → https://api.eu-west-1.staging.example.com/v1
const client = new MyApiClient({
  region: "eu-west-1",
  serverUrlEnvironment: "staging",
});

// Or route all requests to a custom base URL
// → https://api.us-west-2.staging.example.com/v1
const client = new MyApiClient({
  baseUrl: "https://api.us-west-2.staging.example.com/v1",
});
```

#### Python

The generated SDK exposes an `Environment` class:

**`environment.py`**

```python title="environment.py"
class MyApiEnvironment:
    REGIONAL_API_SERVER: MyApiEnvironment

    def __init__(self, *, base: str, auth: str):
        self.base = base
        self.auth = auth


MyApiEnvironment.REGIONAL_API_SERVER = MyApiEnvironment(
    base="https://api.example.com/v1", auth="https://auth.example.com"
)
```

SDK users can select an environment, set URL variables, or pass a custom environment when constructing the client:

```python
from my_api import MyApiClient, MyApiEnvironment

# Use the default environment
# → https://api.example.com/v1
client = MyApiClient()

# Target a specific region and environment via URL variables
# → https://api.eu-west-1.staging.example.com/v1
client = MyApiClient(
    region="eu-west-1",
    server_url_environment="staging",
)

# Or provide custom URLs
client = MyApiClient(
    environment=MyApiEnvironment(
        base="https://api.us-west-2.staging.example.com/v1",
        auth="https://auth.us-west-2.example.com",
    ),
)
```

#### Java

The generated SDK exposes an `Environment` class:

**`Environment.java`**

```java title="Environment.java"
public final class Environment {
    public static final Environment REGIONAL_API_SERVER =
        new Environment(
            "https://api.example.com/v1",
            "https://auth.example.com"
        );
    public static Builder custom() { return new Builder(); }
}
```

SDK users can select an environment, set URL variables, or build a custom environment:

```java
import com.example.api.MyApiClient;
import com.example.api.core.Environment;

// Use the default environment
// → https://api.example.com/v1
MyApiClient client = MyApiClient.builder().build();

// Target a specific region and environment via URL variables
// → https://api.eu-west-1.staging.example.com/v1
MyApiClient client = MyApiClient.builder()
    .region("eu-west-1")
    .serverUrlEnvironment("staging")
    .build();

// Or provide custom URLs
MyApiClient client = MyApiClient.builder()
    .environment(Environment.custom()
        .base("https://api.us-west-2.staging.example.com/v1")
        .auth("https://auth.us-west-2.example.com")
        .build())
    .build();
```

#### Go

The generated SDK exposes an `Environments` variable:

**`environments.go`**

```go title="environments.go"
var Environments = struct {
    RegionalAPIServer Environment
}{
    RegionalAPIServer: Environment{
        Base: "https://api.example.com/v1",
        Auth: "https://auth.example.com",
    },
}
```

SDK users can set URL variables or pass a custom base URL with functional options:

```go
import (
    myapi "github.com/example/my-api/client"
    "github.com/example/my-api/option"
)

// Use the default environment
// → https://api.example.com/v1
client := myapi.NewClient()

// Target a specific region and environment via URL variables
// → https://api.eu-west-1.staging.example.com/v1
client := myapi.NewClient(
    option.WithRegion("eu-west-1"),
    option.WithServerURLEnvironment("staging"),
)

// Or route all requests to a custom base URL
// → https://api.us-west-2.staging.example.com/v1
client := myapi.NewClient(
    option.WithBaseURL("https://api.us-west-2.staging.example.com/v1"),
)
```

> **Note**
>
> To generate a simpler client without server URL variables, set [`serverUrlVariables`](/learn/sdks/legacy/generators/go/configuration#serverurlvariables) to `false` in the Go generator config. The SDK then omits the per-variable client options and the base-URL template interpolation.

#### C\#

The generated SDK exposes an `Environment` class:

**`MyApiEnvironment.cs`**

```csharp title="MyApiEnvironment.cs"
public class MyApiEnvironment
{
    public static readonly MyApiEnvironment RegionalApiServer = new MyApiEnvironment
    {
        Base = "https://api.example.com/v1",
        Auth = "https://auth.example.com",
    };

    public string Base { get; init; }
    public string Auth { get; init; }
}
```

SDK users can set URL variables or a custom environment through `ClientOptions`:

```csharp
using MyApi;

// Use the default environment
// → https://api.example.com/v1
var client = new MyApiClient();

// Target a specific region and environment via URL variables
// → https://api.eu-west-1.staging.example.com/v1
var client = new MyApiClient(new ClientOptions
{
    Region = "eu-west-1",
    ServerUrlEnvironment = "staging",
});

// Or provide custom URLs
var client = new MyApiClient(new ClientOptions
{
    Environment = new MyApiEnvironment
    {
        Base = "https://api.us-west-2.staging.example.com/v1",
        Auth = "https://auth.us-west-2.example.com",
    },
});
```

#### PHP

The generated SDK exposes an `Environments` class:

**`Environments.php`**

```php title="Environments.php"
class Environments
{
    public static function RegionalApiServer(): Environments
    {
        return new self(
            base: 'https://api.example.com/v1',
            auth: 'https://auth.example.com'
        );
    }

    public static function custom(string $base, string $auth): Environments
    {
        return new self(base: $base, auth: $auth);
    }
}
```

SDK users can set URL variables or a custom environment as named constructor arguments:

```php
use MyApi\MyApiClient;
use MyApi\Environments;

// Use the default environment
// → https://api.example.com/v1
$client = new MyApiClient();

// Target a specific region and environment via URL variables
// → https://api.eu-west-1.staging.example.com/v1
$client = new MyApiClient(
    region: 'eu-west-1',
    serverUrlEnvironment: 'staging',
);

// Or provide custom URLs
$client = new MyApiClient(
    environment: Environments::custom(
        base: 'https://api.us-west-2.staging.example.com/v1',
        auth: 'https://auth.us-west-2.example.com',
    ),
);
```

#### Ruby

The generated SDK exposes an `Environment` class:

**`environment.rb`**

```ruby title="environment.rb"
module MyApi
  class Environment
    REGIONAL_API_SERVER = {
      base: "https://api.example.com/v1",
      auth: "https://auth.example.com"
    }.freeze
  end
end
```

SDK users can set URL variables or pass a custom base URL as keyword arguments:

```ruby
# Use the default environment
# → https://api.example.com/v1
client = MyApi::Client.new

# Target a specific region and environment via URL variables
# → https://api.eu-west-1.staging.example.com/v1
client = MyApi::Client.new(
  region: "eu-west-1",
  server_url_environment: "staging"
)

# Or route all requests to a custom base URL
# → https://api.us-west-2.staging.example.com/v1
client = MyApi::Client.new(
  base_url: "https://api.us-west-2.staging.example.com/v1"
)
```

## Setting up server URL templating

Define URL template variables in your API definition and provide a static fallback URL when SDK users don't customize variables:

**`openapi.yml`**

```yaml title="openapi.yml"
servers:
  - url: https://api.{region}.{environment}.example.com/v1
    x-fern-server-name: Default
    x-fern-default-url: https://api.example.com/v1
    variables:
      region:
        default: us-east-1
        enum: [us-east-1, us-west-2, eu-west-1]
      environment:
        default: prod
        enum: [prod, staging, dev]
```

For full configuration details, see [Server names and URL templating in OpenAPI](/learn/api-definitions/openapi/extensions/server-names-and-url-templating).