Thank you for your interest in contributing to the OpenFeature JS Client! This document provides guidelines for contributing to the project, with a focus on the release process.
This is a monorepo managed with Lerna that contains multiple packages:
@datadog/flagging-core- Runtime-agnostic flag-evaluation logic@datadog/openfeature-browser- Browser-specific bindings for OpenFeature@datadog/openfeature-node-server- Node.js server bindings for OpenFeature
The project uses independent versioning, meaning each package can have its own version number. Internal dependencies (e.g., @datadog/flagging-core) are pinned to exact versions on release (via command.version.exact in lerna.json) to prevent version skew.
-
Install dependencies:
yarn install
-
Build all packages:
yarn build
-
Run tests:
yarn test -
Type checking:
yarn typecheck
-
Linting:
yarn lint yarn lint:fix # Auto-fix issues
- Ensure you're not on the
mainbranch (releases should be done from feature branches) - All tests must pass
- Code must be linted and type-checked
- Changes should be committed and pushed
- Proper GitHub secrets must be configured:
NPM_PUBLISH_TOKEN_FLAGGING_CORE- Token for publishing core packageNPM_PUBLISH_TOKEN- Token for publishing browser package
The project supports different build modes that affect how the SDK version is determined:
- Default mode when
BUILD_MODEis not set - SDK version is set to
"dev" - Used during development and testing
- Used for public releases
- SDK version uses the actual version from
lerna.json - This is the mode used for production releases
- Used on staging and production Datadog web app
- SDK version format:
{lerna-version}-{commit-sha} - Example:
0.1.0-alpha.2-a1b2c3d4
The project also supports different SDK setups:
npm(default) - For npm package distributioncdn- For CDN distribution
All packages are published with the latest npm tag.
-
Switch to a feature branch:
# For independent releases (describe what's being released) git checkout -b release/node-server-1.3.0 git checkout -b release/browser-and-node-server-1.3.0 # For unified releases (all packages with same version) git checkout -b release/v1.2.3
-
Ensure internal dependencies use exact versions:
yarn node ./scripts/release/update-peer-dependency-versions.js
This script reads each package's current version and updates internal dependencies (like
@datadog/flagging-core) to use exact versions without the^prefix. This prevents version skew between packages.After running, verify the changes:
git diff packages/*/package.jsonYou should see changes like:
- "@datadog/flagging-core": "^1.2.1" + "@datadog/flagging-core": "1.2.1"
-
Update the version using the CLI:
For independent releases (recommended):
yarn release
This command:
- Validates you're not on the
mainbranch - Runs
lerna version --exact - Prompts for version updates only for changed packages
- Creates version commits and tags per package (e.g.,
@datadog/openfeature-node-server@1.3.0) - Pushes version tags to Github
For unified releases (all packages with same version):
yarn release:all
This command:
- Same as above, but uses
--force-publishto prompt for all packages - Use this when you want to release all packages together with the same version
- Validates you're not on the
-
Open a PR from your release branch and merge it with a merge commit — not a squash.
yarn releasepushes the version tag onto your branch commit. Squashing creates a new commit onmainand orphans that tag, which breaks change detection on the next release (Lerna falls back to an old tag and prompts to version packages that never changed). A merge commit keeps the tag reachable.
Publishing is fully automated via GitHub workflows!
-
Create a GitHub Release:
- Go to the GitHub repository
- Click "Releases" → "Create a new release"
- Set the tag to match your version:
- Independent:
@datadog/openfeature-node-server@1.3.0(publishes only that package) - Unified:
v1.2.1(publishes all packages)
- Independent:
- Add release notes describing your changes or use the
Generate Release Notesbutton - Click "Publish release"
For multiple independent releases: Create a separate GitHub release for each package tag (e.g., one for
@datadog/openfeature-browser@1.3.0and one for@datadog/openfeature-node-server@1.3.0). -
Automated Publishing Workflow:
The
release.yamlworkflow will automatically trigger and:Validation Phase:
- Checks that the GitHub release tag matches the corresponding package version
- Fails fast if validation doesn't pass
Build and Publish Phase:
- Installs dependencies with
yarn install --immutable - Builds all packages in release mode (
BUILD_MODE=release) - Creates package tarballs with
yarn lerna run pack --stream
Publishing Sequence:
For independent releases (
@datadog/pkg@x.y.z):- Publishes only the specified package
- If publishing
browserornode-server, waits forflagging-coreto be available on npm first
For unified releases (
vX.Y.Z):- Publishes
@datadog/flagging-corefirst - Waits for npm registry propagation (up to 5 minutes)
- Publishes
@datadog/openfeature-browser - Publishes
@datadog/openfeature-node-server
# Build all formats (CommonJS and ESM)
cd packages/core
yarn build
# Build CommonJS only
yarn build:cjs
# Build ESM only
yarn build:esm
# Create package tarball
yarn pack# Build all formats (CommonJS, ESM, and bundle)
cd packages/browser
yarn build
# Build bundle for CDN
SDK_SETUP=cdn yarn build:bundle
# Build CommonJS only
yarn build:cjs
# Build ESM only
yarn build:esm
# Create package tarball
yarn pack-
BUILD_MODE: Controls the SDK version formatdev(default) - Development versionrelease- Production release versioncanary- Canary version with commit SHA
-
SDK_SETUP: Controls the SDK setup typenpm(default) - For npm distributioncdn- For CDN distribution
Since this project uses independent versioning:
- Each package has its own version number (stored in its
package.json) yarn releaseprompts for version updates only for changed packages (independent releases)yarn release:allprompts for all packages (unified releases)- Internal dependencies are pinned to exact versions (configured via
command.version.exactinlerna.json) - Version commits and tags are created per package (e.g.,
@datadog/openfeature-node-server@1.3.0)
⚠️ Version policy for@datadog/flagging-core: Internal dependencies are pinned to exact versions (enforced byscripts/internal-deps-validate.sh), so our packages never pull a core update implicitly. From2.0.0onward,flagging-corefollows normal semver — minor/patch for backward-compatible changes, major for breaking ones. Two rules still apply:
- Do not publish new
1.xversions offlagging-core. Legacy consumers still on^1.2.1would pull them and risk version skew; the2.0.0major bump exists to cap those consumers below2.x.- Bumping core does not reach dependents automatically. Because
openfeature-browserandopenfeature-node-serverpin core exactly, you must update each dependent's pin and re-release it (see Step 2) for consumers to pick up the new core.
The GitHub Actions workflow (release.yaml) includes several safety measures:
-
Version Consistency Check:
- Compares GitHub release tag with the corresponding package version
- Ensures tags and package versions are synchronized
-
Dependency Coordination:
- Core package is published first
- Waits for npm registry propagation (up to 5 minutes)
- Browser package gets updated core dependency automatically
-
Build Integrity:
- Uses
BUILD_MODE=releasefor production builds - Replaces build environment variables correctly
- Creates both npm packages and CDN bundles
- Uses
-
Run all tests:
yarn test -
Type checking:
yarn typecheck
-
Linting:
yarn lint
-
Build verification:
yarn clean yarn build yarn build:bundle
-
Package creation test:
yarn version # Pins internal dependencies and creates package tarballs
-
Release from main branch:
- Error: "please do not release from
mainbranch" - Solution: Create a feature branch for releases
- Error: "please do not release from
-
Version mismatch in GitHub workflow:
- Error: "Release tag doesn't match lerna.json version"
- Solution: Ensure the GitHub release tag exactly matches
v{version}format where{version}is fromlerna.json
-
Build environment issues:
- Ensure
BUILD_MODEandSDK_SETUPare set correctly - Check that all dependencies are installed
- Ensure
-
Version synchronization issues:
- Run
yarn node ./scripts/release/update-peer-dependency-versions.jsto pin internal dependencies - Verify internal dependencies use exact versions (no
^prefix)
- Run
-
GitHub workflow failures:
- Check the Actions tab for detailed error logs
- Ensure GitHub secrets are properly configured:
NPM_PUBLISH_TOKEN_FLAGGING_COREfor core packageNPM_PUBLISH_TOKENfor browser package
- Verify the release tag matches the version in
lerna.json
-
npm registry propagation delays:
- The workflow waits up to 5 minutes for the core package to be available
- If this fails, it may indicate npm registry issues
- Check npm status page or try republishing manually
-
Webpack build issues:
- Ensure all TypeScript configurations are valid
- Check that webpack configurations in each package are correct
- Verify all required dependencies are installed
- Check the README.md for basic project information
- Review the scripts in the
scripts/directory for implementation details - Check the GitHub Actions tab for workflow status and logs
- Examine the
scripts/cliscript for available commands (release,release_all,version,typecheck,lint) - Open an issue on GitHub for bugs or feature requests
If the automated workflow fails and you need to publish manually:
-
Build packages:
BUILD_MODE=release yarn build yarn version
-
Publish core package:
cd packages/core npm publish --tag latest -
Wait for propagation, then publish remaining packages:
cd packages/browser npm publish --tag latest cd ../node-server npm publish --tag latest
All third-party dependency licenses are tracked in LICENSE-3rdparty.csv. This file is
auto-generated and must be kept up to date whenever dependencies change. CI will fail
if it is stale.
Re-generate the file whenever you add, remove, or update a dependency in any package.json.
| Requirement | Details |
|---|---|
| Python 3.11.12 | pyenv install 3.11.12 && pyenv local 3.11.12 |
| Go 1.23+ | Required by dd-license-attribution |
| dd-license-attribution | pip install dd-license-attribution (repo) |
| GITHUB_TOKEN | See below |
For Datadog employees, see the internal dd-license-attribution guide.
If you already use the GitHub CLI, the easiest option is:
export GITHUB_TOKEN=$(gh auth token)Otherwise, create a fine-grained personal access token with read access to Contents and Metadata at https://github.com/settings/personal-access-tokens and export it:
export GITHUB_TOKEN="github_pat_..."export GITHUB_TOKEN=$(gh auth token)
yarn licenses:generateThis overwrites LICENSE-3rdparty.csv with the latest data. Commit the result.
yarn licenses:validateThis checks that every npm package in yarn.lock has a corresponding entry in the CSV.
No external tools or tokens are needed — it runs in CI the same way. If it fails, run
yarn licenses:generate and commit the result.
- Use TypeScript for all new code
- Follow the existing code style and patterns
- Run
yarn lint:fixbefore committing - Ensure all tests pass before submitting changes
Follow conventional commit format with gitmoji:
✨ feat:for new features🐛 fix:for bug fixes📝 docs:for documentation changes🎨 style:for formatting changes♻️ refactor:for code refactoring✅ test:for test changes👷 chore:for maintenance tasks
Example: ✨ feat(browser): add new flag evaluation method