# What Is the TTL for Session Pinning Entries in WorkWeave Router?

> Discover the default 30-minute TTL for session pinning entries in WorkWeave Router. Learn how to configure this setting using the ROUTER_SESSION_PIN_TTL environment variable for optimized performance.

- Repository: [Weave/router](https://github.com/workweave/router)
- Tags: api-reference
- Published: 2026-08-30

---

**The TTL for session pinning entries in WorkWeave Router defaults to 30 minutes**, configurable via the `ROUTER_SESSION_PIN_TTL` environment variable.

WorkWeave Router uses **session pinning** to maintain consistent routing decisions for user sessions across multiple requests. Understanding the **TTL for session pinning entries in WorkWeave Router** is essential for tuning session persistence and ensuring stale routing data is purged efficiently. The system calculates expiration using a `PinnedUntil` timestamp that is set to the current time plus the configured TTL duration.

## How the Session Pin TTL Is Configured

The router determines the lifespan of a session pin through the **`ROUTER_SESSION_PIN_TTL`** environment variable. When this variable is unset, the system falls back to a hardcoded default of **30 minutes** (`30 * time.Minute`).

According to the WorkWeave Router source code, a configuration helper—typically `SessionPinTTL()` in [`internal/config/config.go`](https://github.com/workweave/router/blob/main/internal/config/config.go)—parses this environment variable and returns the appropriate `time.Duration`. This value is applied whenever a new pin is created or updated.

## Implementation Details in the Source Code

### The Pin Struct and PinnedUntil Field

At the core of the TTL mechanism is the `Pin` struct defined in [`internal/router/sessionpin/store.go`](https://github.com/workweave/router/blob/main/internal/router/sessionpin/store.go) (lines 55-58). This struct includes a **`PinnedUntil`** field that stores the expiration timestamp for each routing decision.

```go
// Pin represents a session routing decision with expiration
type Pin struct {
    SessionKey     string
    Role           string
    InstallationID string
    Provider       string
    Model          string
    PinnedUntil    time.Time  // Expiration timestamp
}

```

When the router pins a session to a specific provider or model, it calculates `PinnedUntil` as the current time plus the configured TTL.

### PostgreSQL Store Implementation

The concrete implementation in [`internal/postgres/session_pin_repo.go`](https://github.com/workweave/router/blob/main/internal/postgres/session_pin_repo.go) handles the persistence logic. In the `Upsert` method (lines 78-85), the repository reads the TTL from the configuration and sets the `PinnedUntil` field accordingly:

```go
// Upsert creates or updates a session pin with TTL
func (r *SessionPinRepo) Upsert(ctx context.Context, pin sessionpin.Pin) error {
    pin.PinnedUntil = time.Now().Add(r.config.SessionPinTTL())
    // ... SQL INSERT/UPDATE logic ...
}

```

This ensures every pinned session receives the same TTL duration from the moment it is written to the database.

### Expired Pin Cleanup

The `Store` interface defines a **`SweepExpired`** method (lines 37-38 in [`internal/router/sessionpin/store.go`](https://github.com/workweave/router/blob/main/internal/router/sessionpin/store.go)) that the background janitor invokes periodically. This method removes rows where `PinnedUntil` is in the past, guaranteeing that stale routing decisions do not accumulate in PostgreSQL.

## Practical Configuration Examples

To use the default 30-minute TTL, no additional configuration is required. The router automatically applies this duration when creating pins:

```go
// Using the default 30-minute TTL
pin := sessionpin.Pin{
    SessionKey:     sessionKey,
    Role:           sessionpin.DefaultRole,
    InstallationID: installationID,
    Provider:       provider,
    Model:          model,
    PinnedUntil:    time.Now().Add(config.SessionPinTTL()), // 30 minutes
}

if err := store.Upsert(ctx, pin); err != nil {
    log.Error("failed to upsert session pin", "err", err)
}

```

To override the default, export the environment variable before starting the router:

```bash

# Set TTL to 1 hour

export ROUTER_SESSION_PIN_TTL=1h

# Start the router

./router

```

With this configuration, all new session pins will expire after one hour instead of 30 minutes.

## Summary

- The **default TTL for session pinning entries in WorkWeave Router is 30 minutes**.
- Override the default by setting the **`ROUTER_SESSION_PIN_TTL`** environment variable to any valid Go duration string.
- The `Pin` struct in [`internal/router/sessionpin/store.go`](https://github.com/workweave/router/blob/main/internal/router/sessionpin/store.go) tracks expiration via the **`PinnedUntil`** field.
- The PostgreSQL repository in [`internal/postgres/session_pin_repo.go`](https://github.com/workweave/router/blob/main/internal/postgres/session_pin_repo.go) applies the TTL during the upsert operation.
- The **`SweepExpired`** method periodically removes stale pins based on the `PinnedUntil` timestamp.

## Frequently Asked Questions

### What is the default session pinning TTL in WorkWeave Router?

The default TTL is **30 minutes**. This value is hardcoded as `30 * time.Minute` and applies when the `ROUTER_SESSION_PIN_TTL` environment variable is not configured.

### How do I change the session pinning TTL?

Set the **`ROUTER_SESSION_PIN_TTL`** environment variable to your desired duration (e.g., `1h`, `30m`, `2h30m`) before starting the router. The configuration parser accepts any valid Go duration string.

### How does WorkWeave Router handle expired session pins?

The router runs a background cleanup process that invokes the `SweepExpired` method defined in [`internal/router/sessionpin/store.go`](https://github.com/workweave/router/blob/main/internal/router/sessionpin/store.go). This method queries for pins where `PinnedUntil` is in the past and deletes them from the PostgreSQL store.

### What happens if ROUTER_SESSION_PIN_TTL is set to an invalid value?

If the environment variable contains an invalid duration string, the configuration helper will typically fail during startup or fall back to the default 30-minute TTL, depending on the specific error handling implemented in the config package. Always use valid Go duration formats like `30m` or `1h30m`.