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

# Go SDK - Config values

> How config values are typed, why numbers are json.Number, and typed reads with GetConfigAs.

*Changed in v0.11.0.*

`GetConfig` returns the decoded JSON value. The type mapping is:

| JSON    | Go               |
| ------- | ---------------- |
| string  | `string`         |
| number  | `json.Number`    |
| boolean | `bool`           |
| object  | `map[string]any` |
| array   | `[]any`          |
| null    | `nil`            |

```go theme={null}
raw, ok := client.GetConfig("max_items")
if !ok {
    // key is not in the cache
}
limit, err := raw.(json.Number).Int64()
```

## Why numbers are `json.Number`

Because `float64` cannot hold every integer a config value might be.

`encoding/json` decodes a JSON number into `float64` when the destination is an `any`,
and `float64` has a 53-bit mantissa. Above 2^53 it starts rounding: a snowflake id, a
Stripe amount in minor units, a nanosecond timestamp all come back as a *different
number*, and nothing anywhere reports a problem. `9007199254740993` becomes
`9007199254740992`.

`json.Number` is the exact decimal text the backend sent, converted only when you ask:

```go theme={null}
n := raw.(json.Number)
n.String()   // "9007199254740993" - exactly what the server stored
n.Int64()    // 9007199254740993, nil
n.Float64()  // 9.007199254740992e+15, nil - lossy, and you chose it
```

`Int64` returns an error for a fractional value or one outside `int64`'s range, so a
mistake surfaces as an error instead of a wrong number.

This is the same decision the other Nexus SDKs make in their own idiom: the SDK owns
the representation of a config value rather than inheriting a lossy one from whatever
its JSON library happened to reach for.

## Typed reads with `GetConfigAs`

Asserting and converting by hand gets tedious, so decode into your own type instead:

```go theme={null}
type Endpoint struct {
    Host string `json:"host"`
    Port int    `json:"port"`
}

endpoint, err := nexus.GetConfigAs[Endpoint](client, "db.endpoint")
if err != nil {
    return err
}
```

It works for scalars too:

```go theme={null}
limit, err := nexus.GetConfigAs[int64](client, "max_items")
hosts, err := nexus.GetConfigAs[[]string](client, "allowed_hosts")
```

`GetConfigAs` is a package-level function rather than a method because Go methods
cannot have type parameters.

Decoding happens from the **exact bytes the backend sent**, not from the already
decoded value, so your `json` tags, embedded types and custom `UnmarshalJSON` all
behave exactly as they would if you had unmarshalled the response yourself - and no
precision is lost on the way through.

| Returns                | When                                                 |
| ---------------------- | ---------------------------------------------------- |
| `ErrConfigNotFound`    | The key is not in the cache. Check with `errors.Is`. |
| a wrapped decode error | The stored value does not fit `T`.                   |

## Mutation safety

`GetConfig` and `GetAllConfigs` return deep copies of object and array values, so a
caller mutating a returned `map[string]any` or `[]any` cannot reach into the shared
cache or race a background refresh. Scalars are copied by value.

## Reading everything at once

```go theme={null}
for key, value := range client.GetAllConfigs() {
    fmt.Printf("%s = %v (%T)\n", key, value, value)
}
```

Public (`wxp_`) keys receive the same configs and flags a secret key does. What they do
not receive is secrets, which are absent from the sync response entirely.

## Next

* [API reference](/sdks/go/api-reference)
* [Configuration](/sdks/go/configuration)
* [Caching behaviour](/sdks/go/caching-behaviour)
