{"id":15857,"library":"tggl-client","title":"Tggl Client SDK","description":"The `tggl-client` package provides a TypeScript SDK for integrating Tggl feature flags into both client-side (browsers, React Native) and server-side (Node.js) applications. Currently at version 3.2.2, the library maintains an active release cadence with frequent updates and bug fixes, as evidenced by recent v3.x releases. Version 3 represents a complete rewrite focused on improved reliability, fault tolerance, and maintainability, introducing a simpler API, better error handling, and automatic HTTP retries via `ky`. A key differentiator is its enforcement of feature flag best practices, specifically by removing the `isActive` method and making the default value a required argument for the `get` method since v2.0.0, guiding developers to always handle the absence of a flag gracefully. It also offers built-in storage options for Postgres, Redis, and Static storage for server-side usage, requiring corresponding peer dependencies like `pg` or `redis` for these features. The SDK supports Node.js environments version 20.0.0 and above.","status":"active","version":"3.2.2","language":"javascript","source_language":"en","source_url":"https://github.com/Tggl/js-tggl-client","tags":["javascript","Tggl","Feature flag","Feature toggle","A/B testing","Remote config","Kill switch","typescript"],"install":[{"cmd":"npm install tggl-client","lang":"bash","label":"npm"},{"cmd":"yarn add tggl-client","lang":"bash","label":"yarn"},{"cmd":"pnpm add tggl-client","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency required for potential S3-backed storage, though not explicitly mentioned for 'built-in storages'.","package":"@aws-sdk/client-s3","optional":true},{"reason":"Peer dependency required for using the built-in Postgres storage option for server-side clients.","package":"pg","optional":true},{"reason":"Peer dependency required for using the built-in Redis storage option for server-side clients.","package":"redis","optional":true}],"imports":[{"note":"Used for client-side applications (browsers, React Native) requiring a client API key. It is a named export.","wrong":"import TgglClient from 'tggl-client'","symbol":"TgglClient","correct":"import { TgglClient } from 'tggl-client'"},{"note":"Used for server-side Node.js applications. While CJS might work in some setups, ESM import is the modern and recommended approach, especially with Node.js >=20. It is a named export.","wrong":"const { TgglLocalClient } = require('tggl-client')","symbol":"TgglLocalClient","correct":"import { TgglLocalClient } from 'tggl-client'"},{"note":"Used for server-side clients to provide a basic, in-memory storage solution for flags. Other storage options like PostgresStorage and RedisStorage are also named exports.","symbol":"StaticStorage","correct":"import { StaticStorage } from 'tggl-client'"}],"quickstart":{"code":"import { TgglClient, TgglLocalClient, StaticStorage } from 'tggl-client';\n\nasync function runFeatureFlagExample() {\n  // It's highly recommended to use environment variables for API keys in production\n  const clientApiKey = process.env.TGGL_CLIENT_API_KEY ?? 'TGGL_CLIENT_KEY_XXX';\n  const serverApiKey = process.env.TGGL_SERVER_API_KEY ?? 'TGGL_SERVER_KEY_YYY';\n\n  // --- Client-side usage example (e.g., browser, React Native) ---\n  console.log(\"\\n--- Initializing TgglClient (Client-side) ---\");\n  const client = new TgglClient({\n    apiKey: clientApiKey,\n    initialContext: { userId: 'browser-user-123', plan: 'free' },\n  });\n\n  try {\n    await client.waitReady(); // Wait for initial flags to be fetched\n    if (client.get('enable-dark-mode', false)) {\n      console.log('Client: Dark mode is ENABLED for this user!');\n    } else {\n      console.log('Client: Dark mode is DISABLED or not found, using default.');\n    }\n\n    const welcomeMessage = client.get('welcome-banner-text', 'Hello there!');\n    console.log(`Client: Welcome message: \"${welcomeMessage}\"`);\n\n  } catch (error) {\n    console.error(\"Error with TgglClient initialization or flag evaluation:\", error);\n  }\n\n  // --- Server-side usage example (e.g., Node.js backend) ---\n  console.log(\"\\n--- Initializing TgglLocalClient (Server-side) ---\");\n  // For production, consider PostgresStorage or RedisStorage with proper configuration\n  const storage = new StaticStorage(); \n  const localClient = new TgglLocalClient({\n    apiKey: serverApiKey,\n    storage, // Pass the storage instance\n    refreshInterval: 60000, // Refresh flags from Tggl API every minute\n  });\n\n  try {\n    await localClient.waitReady(); // Wait for initial flags to be fetched\n\n    const serverContext = { userId: 'server-user-456', environment: 'production' };\n    if (localClient.get(serverContext, 'new-api-endpoint', false)) {\n      console.log('Server: Using new API endpoint for this context!');\n    } else {\n      console.log('Server: Using old API endpoint.');\n    }\n\n    const featureVariant = localClient.get({ userId: 'another-user-789' }, 'feature-x-variant', 'control');\n    console.log(`Server: 'feature-x-variant' for 'another-user-789' is: ${featureVariant}`);\n\n  } catch (error) {\n    console.error(\"Error with TgglLocalClient initialization or flag evaluation:\", error);\n  } finally {\n    // Important: Stop background processes for local client when done (e.g., on server shutdown)\n    localClient.stopReporting?.(); \n    localClient.stopRefreshing?.();\n  }\n}\n\nrunFeatureFlagExample();\n","lang":"typescript","description":"This quickstart demonstrates the initialization and usage of both TgglClient (for client-side) and TgglLocalClient (for server-side) to evaluate feature flags with different contexts and built-in storage options."},"warnings":[{"fix":"Replace any calls to `client.isActive('flag-name')` with `client.get('flag-name', false)` or similar, and ensure all `client.get('flag-name')` calls are updated to `client.get('flag-name', defaultValue)`.","message":"Version 2.0.0 introduced significant breaking changes: the `isActive` method was removed entirely, and the `get` method now requires a default value as a mandatory argument. This change enforces best practices, preventing code from relying on a flag's existence and instead promoting graceful fallbacks.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Review the v3 release notes and documentation for any changes to client configuration or behavior. Ensure your Node.js environment meets the `>=20.0.0` requirement. Verify all peer dependencies are correctly installed if using built-in storages.","message":"Version 3.0.0 was a complete rewrite, focusing on reliability and fault tolerance. While the core API (`get` method) remained largely consistent with v2, internal mechanisms changed (e.g., `ky` for HTTP requests), and API simplifications might affect advanced usage patterns or custom integrations. The SDK now requires Node.js >=20.0.0.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Always use `TgglClient` with a client API key in frontend applications and `TgglLocalClient` with a server API key in backend applications. `TgglLocalClient` also requires a storage mechanism (e.g., `StaticStorage`, `PostgresStorage`, `RedisStorage`).","message":"It's crucial to distinguish between `TgglClient` (for client-side environments like browsers or React Native) and `TgglLocalClient` (for server-side Node.js applications). Using the wrong client type can lead to incorrect flag evaluations, performance issues, or security vulnerabilities (e.g., exposing server API keys on the client).","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always `await client.waitReady()` immediately after client initialization to ensure that the initial set of flags has been loaded before any `get()` calls are made. This is essential for reliable flag evaluation.","message":"The `waitReady()` method is asynchronous and must be awaited before attempting to retrieve flag values. If `get()` is called before the client is ready, it may return default values prematurely or encounter errors, as flags might not have been fetched yet.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Update your code to use the `get` method with a default boolean value instead, e.g., `client.get('feature-name', false)`.","cause":"Attempting to call the `isActive` method, which was removed in `tggl-client` v2.0.0.","error":"TypeError: client.isActive is not a function"},{"fix":"Provide a default value for the flag, e.g., `client.get('feature-name', true)` or `localClient.get(context, 'feature-name', 'default_value')`.","cause":"Calling the `get` method without providing a required default value as the second argument (for client-side) or third argument (for server-side with context). This became mandatory in `tggl-client` v2.0.0.","error":"Argument of type 'undefined' is not assignable to parameter of type 'string | boolean | number | null | Record<string, any>'"},{"fix":"Use ESM `import` statements (e.g., `import { TgglClient } from 'tggl-client';`) and ensure your project is configured for ESM (e.g., `\"type\": \"module\"` in `package.json`). If running in Node.js, ensure your environment supports ESM.","cause":"Attempting to import `tggl-client` using CommonJS `require()` syntax in an environment configured for ESM, or when the package's primary entry point is ESM-only.","error":"ERR_REQUIRE_ESM"},{"fix":"Verify your `apiKey` is correct and has the necessary permissions. Check network connectivity to `tggl.io` (or your configured `baseUrl`). Review Tggl's status page or logs for potential service outages or errors. Ensure firewalls are not blocking access.","cause":"The `waitReady()` method timed out, indicating an issue with fetching flags from the Tggl API (e.g., incorrect API key, network issues, or service unavailability).","error":"Error: Tggl client is not ready after Xms"}],"ecosystem":"npm"}