# How to Manage Toolkit Versions for Production Stability in Composio

> Ensure production stability by managing Composio toolkit versions effectively. Pin versions globally, override per call, and use environment variables for secure CI/CD deployment.

- Repository: [Composio/composio](https://github.com/composiohq/composio)
- Tags: best-practices
- Published: 2026-02-19

---

**Pin toolkit versions globally via the Composio constructor, override per-call when needed, and use environment variables for CI/CD to ensure deterministic agent behavior across releases.**

The Composio SDK provides a robust versioning system that lets you lock individual toolkits (GitHub, Gmail, Slack, etc.) to specific releases, preventing unexpected breaking changes when providers update their APIs. By managing toolkit versions explicitly, you guarantee that your AI agents execute with predictable request and response schemas regardless of upstream changes. This guide walks through the configuration hierarchy, source code implementation, and production patterns used in the `ComposioHQ/composio` repository.

## Understanding the Versioning Architecture

The SDK implements toolkit versioning through a type-safe hierarchy that resolves versions at runtime. At the core, **`ToolkitVersionParam`** in [`ts/packages/core/src/types/tool.types.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/types/tool.types.ts) defines the input shape as either a string (`"latest"` or a global version) or an object mapping toolkit slugs to specific versions.

During SDK initialization in [`ts/packages/core/src/utils/sdk.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/sdk.ts), this parameter is normalized into **`ToolkitVersions`**, an object that guarantees every toolkit has an explicit version entry. The resolution logic lives in [`ts/packages/core/src/utils/toolkitVersion.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/toolkitVersion.ts), where the **`getToolkitVersion`** helper extracts the effective version for a given slug, defaulting to `"latest"` when no explicit mapping exists.

Both `Tools` and `Triggers` models store this configuration at construction time. In [`ts/packages/core/src/models/Tools.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/Tools.ts) (lines 72-87) and [`ts/packages/core/src/models/Triggers.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/Triggers.ts) (lines 75-85), the SDK attaches the resolved `toolkitVersions` to every outgoing API request, ensuring the backend receives the correct version identifier.

## Configuration Hierarchy

The SDK merges version specifications across three layers, with later layers taking precedence over earlier ones:

1. **Global SDK level** – Set once in `new Composio({ toolkitVersions: … })` and inherited by all subsequent calls.
2. **Instance level** – Override when constructing individual `Tools` or `Triggers` instances directly.
3. **Per-call level** – Pass `toolkit_versions` inline to `tools.execute()` for single-use overrides.

This merge order (**global → instance → call**) is verified by the test suites in [`ts/packages/core/test/models/tools.test.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/test/models/tools.test.ts) and [`ts/packages/core/test/core/versions.test.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/test/core/versions.test.ts).

## Production Patterns

### Pinning Versions Globally

For production stability, define a global version mapping in your SDK initialization. This approach ensures every tool execution uses the tested toolkit release unless explicitly overridden.

```typescript
import { Composio } from '@composio/core';

const composio = new Composio({
  apiKey: process.env.COMPOSIO_API_KEY!,
  // Lock GitHub and Gmail to known stable versions.
  toolkitVersions: {
    github: '20251201_01',
    gmail:  '20250909_00',
    // Toolkits omitted here default to "latest".
  },
});

```

All API calls made through `composio.tools` will now use these pinned versions.

### Overriding for Single Executions

When testing new toolkit releases or handling edge cases, override the version for a specific call without affecting global configuration:

```typescript
const result = await composio.tools.execute('GITHUB_CREATE_REPO', {
  userId: 'user-123',
  arguments: { name: 'my-repo' },
  // Force a specific GitHub version just for this invocation.
  toolkit_versions: { github: '20251115_00' },
});

```

The SDK injects this inline mapping into the request body at the call site in [`ts/packages/core/src/models/Tools.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/Tools.ts) (line 779).

### Loading from Environment Variables

For CI/CD pipelines and containerized deployments, the SDK automatically reads version mappings from environment variables prefixed with `COMPOSIO_TOOLKIT_`. In [`ts/packages/core/src/utils/sdk.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/sdk.ts) (lines 73-105), the constructor scans for these variables and merges them into the global configuration.

```bash
export COMPOSIO_TOOLKIT_GITHUB=20251201_01
export COMPOSIO_TOOLKIT_SLACK=20250930_02

```

```typescript
const composio = new Composio({ apiKey: process.env.COMPOSIO_API_KEY! });
// Versions are loaded from environment automatically.

```

This pattern enables version updates without code changes or redeployment.

### Debugging Effective Versions

To verify which version resolves at runtime, use the `getToolkitVersion` utility:

```typescript
import { getToolkitVersion } from '@composio/core/utils/toolkitVersion';

const version = getToolkitVersion('github', composio.config.toolkitVersions);
console.log('Effective GitHub toolkit version:', version);
// Output: "20251201_01"

```

This helper implements the fallback logic defined in [`ts/packages/core/src/utils/toolkitVersion.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/toolkitVersion.ts) (lines 10-21), showing exactly which version applies after environment and configuration merging.

## Why Version Pinning Matters for Production

Pinning toolkit versions delivers three critical production benefits:

- **API Stability** – Toolkits evolve with new fields and changed semantics; locking a version guarantees consistent request/response shapes.
- **Predictable Billing** – Newer toolkit versions may introduce paid features; explicit versioning prevents surprise costs.
- **Regression Safety** – If a new version breaks a workflow, roll back by updating the version mapping rather than redeploying code.

## Summary

- Define global toolkit versions in the `Composio` constructor to set a baseline for all operations.
- Override versions per-call using the `toolkit_versions` parameter in `tools.execute()` for targeted testing.
- Use `COMPOSIO_TOOLKIT_*` environment variables to configure versions in CI/CD without code changes.
- Reference [`ts/packages/core/src/utils/toolkitVersion.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/toolkitVersion.ts) for resolution logic and [`ts/packages/core/src/models/Tools.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/Tools.ts) for request injection.
- Validate your configuration with the test patterns found in [`ts/packages/core/test/core/versions.test.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/test/core/versions.test.ts).

## Frequently Asked Questions

### How does the SDK handle toolkit versions if I don't specify any?

When no explicit version is provided, the SDK defaults to `"latest"` for all toolkits. This fallback is implemented in [`ts/packages/core/src/utils/toolkitVersion.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/toolkitVersion.ts), where `getToolkitVersion` returns `"latest"` if the toolkit slug is absent from the configuration object.

### Can I mix string and object formats for toolkitVersions?

Yes. The `ToolkitVersionParam` type accepts either a string (applying to all toolkits) or an object mapping specific slugs to versions. In [`ts/packages/core/src/utils/sdk.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/utils/sdk.ts), the SDK normalizes string inputs into object format to ensure consistent handling across the codebase.

### Do toolkit versions affect both tools and triggers?

Yes. Both the `Tools` model ([`ts/packages/core/src/models/Tools.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/Tools.ts)) and the `Triggers` model ([`ts/packages/core/src/models/Triggers.ts`](https://github.com/ComposioHQ/composio/blob/main/ts/packages/core/src/models/Triggers.ts)) store the `toolkitVersions` configuration and inject them into respective API requests, ensuring consistent versioning across actions and event subscriptions.

### What happens if I specify a version that doesn't exist?

The SDK forwards the version identifier to the Composio API backend. If the version is invalid, the API returns an error at request time. The SDK itself does not validate version strings locally; it only resolves which version identifier to send based on the configuration hierarchy.