Skip to content

feat(docs): RFC to clarify _unstable naming convention for public APIs#35694

Open
dmytrokirpa wants to merge 2 commits intomicrosoft:masterfrom
dmytrokirpa:docs/deprecate-unstable-rfc
Open

feat(docs): RFC to clarify _unstable naming convention for public APIs#35694
dmytrokirpa wants to merge 2 commits intomicrosoft:masterfrom
dmytrokirpa:docs/deprecate-unstable-rfc

Conversation

@dmytrokirpa
Copy link
Contributor

@dmytrokirpa dmytrokirpa commented Jan 22, 2026

Summary

This RFC proposes deprecating and renaming all public API exports with the _unstable suffix in stable Fluent UI React v9 packages. The current naming convention creates confusion about API stability guarantees and blocks the introduction of truly experimental features.

Problem Statement

Currently, ~62 packages export ~1,300+ APIs with the _unstable suffix (e.g., useBadge_unstable, renderBadge_unstable). Despite the naming suggesting volatility, these APIs are:

  • Fully documented and supported
  • Subject to standard semantic versioning
  • Used in production environments
  • Treated as stable public APIs

This creates three main issues:

  1. Misleading naming: The suffix suggests APIs might change at any time, contradicting their actual stability guarantees
  2. Blocked innovation: No clear naming convention for truly experimental features that can change/be removed without notice
  3. Documentation confusion: Requires constantly explaining that _unstable doesn't actually mean unstable

Proposed Solution

Three coordinated changes:

  1. Remove _unstable suffix from stable APIs

    • useBadge_unstableuseBadge
    • renderBadge_unstablerenderBadge
    • useBadgeStyles_unstableuseBadgeStyles
  2. Maintain backward compatibility through deprecated re-exports

    export const useBadge_unstable = useBadge; // @deprecated
  3. Reserve UNSTABLE_ prefix (all caps) exclusively for experimental features

    export const UNSTABLE_useExperimentalFeature = () => {
      /* ... */
    };

Migration Support

  • Automated codemod: npx @fluentui/codemods v9-remove-unstable-suffix
  • Deprecation warnings in current release
  • Breaking change only in next major version
  • Clear documentation and partner outreach

Timeline

  • Feedback period: Through 2026-02-15
  • Implementation: v9.x release (2026-03 to 2026-04)
  • Migration period: v9.x through next major release
  • Cleanup: Remove deprecated exports in next major version

Is this a breaking change?

No - deprecated re-exports maintain full backward compatibility. The removal of deprecated exports in the next major release will be a breaking change following standard major version semantics.

Related Issue(s)

This RFC addresses long-standing confusion around API stability and enables clearer communication about experimental features.

@github-actions github-actions bot added the Type: RFC Request for Feedback label Jan 22, 2026
@dmytrokirpa dmytrokirpa changed the title feat(docs): introduce RFC to clarify _unstable naming convention for public APIs feat(docs): RFC to clarify _unstable naming convention for public APIs Jan 22, 2026
@github-actions
Copy link

github-actions bot commented Jan 22, 2026

📊 Bundle size report

✅ No changes found

@github-actions
Copy link

Pull request demo site: URL

@dmytrokirpa dmytrokirpa self-assigned this Jan 27, 2026
@dmytrokirpa dmytrokirpa marked this pull request as ready for review January 27, 2026 14:20
@dmytrokirpa dmytrokirpa requested review from a team as code owners January 27, 2026 14:20
Copy link
Contributor

@Hotell Hotell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left comments/questions.

we should probably split this into 2 RFCs to proceed faster

1 - removing/deprecating _unstable which we have probably agreement to proceed
2 - experimntal API approach

- **RFC Approval & Feedback**: 3 weeks (deadline: 2026-02-15)

- Gather core maintainer consensus on approach
- Finalize codemod RFC in parallel
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we probably dont need to proceed with this change with the codemod as dependency

one negative aspect of immediate enablement via "automating" the switch to different symbols would force whole chain of pressure on all teams needing to bump to latest fluent in order to not break runtime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not going to force anyone switch over. Folks can choose to move to the new APIs if they want to avoid using deprecated APIs, but the old ones will still be available, so nothing will break at runtime.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what I meant:

Scenario 1 🚨:

  • there is lib-A/sub-app-A that bumps to latest and applies codemod

  • there is lib-B/app-B` that uses A, but it's on older version of fluent,

  • A runs the codemod and ships new version

  • B is forced to be on the same version ( which should happen eventually ) but if that is not synced -> they would have runtime issue/broken app.

Scenario 2 ✅:

Fluent is part of sandbox env exposing API for devs to provide custom code.

once the sandbox applies codemod all users will all good if sandbox doesn't expose fluent apis in an explicit way where the transform could break the contract

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand what you mean, but if we're talking about renaming useX_unstable to useX via codemod, then both apps should be fine, as it's a alias to the same thing/reference, and we're keeping both exports - so there shouldn't be any runtime errors.

Copy link
Contributor

@Hotell Hotell Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that works,

i meant this scenario:

// sandbox api / lib / app A
export {useX_unstable } from '@fluentui/react-components' 
// ⬇️
export {useX } from '@fluentui/react-components' 
// user code in sandbox / lib / app B
// 🚨
import {useX_unstable} from '@org/ui'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that works,

i meant this scenario:

// sandbox api / lib / app A
export {useX_unstable } from '@fluentui/react-components' 
// ⬇️
export {useX } from '@fluentui/react-components' 
// user code in sandbox / lib / app B
// 🚨
import {useX_unstable} from '@org/ui'

Are you talking about breaking changes caused by the codemod? I think that's on whoever runs the codemod, not the codemod itself, since it just did its job and moved things away from deprecated APIs.


Provide automated codemod to help consumers migrate with minimal manual effort:

- **Command**: `npx @fluentui/codemods v9-remove-unstable-suffix`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of scope for this PR but here is the gist how I envision our tools (because codemod package is already taken for v8 related things):

  • we ship @fluentui/cli which would have various sub-commands for various things we might need as we progress

migrate

  • migration defined in json file ( similar approach as nx )
    @fluentui/cli migrate --run-migrations=migrations.json

  • invoking particular migration directly
    @fluentui/cli migrate remove-unstable-suffix

report

@fluentui/cli report


Node           : 22.21.1
OS             : darwin-arm64
Native Target  : aarch64-macos
npm            : 10.9.4

@fluentui/react-components                     : 9.0.1
@fluentui-contrib/foo-bar                 : 0.11.2

stats

  • scans codebase path and generates report for usages of all fluent apis ( imports, props, etc )
    @fluentui/cli stats <path>

agent

  • setups Skills, mcp etc
  • @fluentui/cli agent init


1. Remove the `_unstable` suffix from stable APIs
2. Maintain backward compatibility through deprecated re-exports
3. Reserve `UNSTABLE_` prefix exclusively for experimental features
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suffix:

  • to avoid "confusion" we should probably go with EXPERIMENTAL_ prefix

experimental api exposure

  • while exposing these directly from existing packages is convenient for both maintainers and consumers it might generate side effects causing issues with bundling and tree shaking in user land. for these reason it might be probably best to expose /experimental api endpoints

experimental api removal/change

  • to not break users we will need to keep this in for 1-2 major version minimum and we cannot change those APIs as well as they are part of STABLE packages. with this in mind besides having a "prefix" to denote to user that this is experimental it acts as stable from semver POV

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suffix:

to avoid "confusion" we should probably go with EXPERIMENTAL_ prefix
experimental api exposure

while exposing these directly from existing packages is convenient for both maintainers and consumers it might generate side effects causing issues with bundling and tree shaking in user land. for these reason it might be probably best to expose /experimental api endpoints

I'm fine with both suggestions of going with EXPERIMENTAL_ prefix and /experimental entry-points for packages

experimental api removal/change

to not break users we will need to keep this in for 1-2 major version minimum and we cannot change those APIs as well as they are part of STABLE packages. with this in mind besides having a "prefix" to denote to user that this is experimental it acts as stable from semver POV

The whole point was to allow having experimental APIs that could be changed/removed and not considering them a part of public contract until they finalized/moved to stable. If we can't establish this convention for some reason then there is no point of introducing this pattern, we just might only need to do clean up and that's it

/**
* @deprecated Use `useBadge` instead. Will be removed in the next major release.
*/
export const useBadge_unstable = useBadge;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious what's the opinion about doubling our API surface because of this change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree that's not ideal scenario, but we need it to make sure everything stays backward compatible


**Criteria for `UNSTABLE_` prefix:**

- Explicitly documented as experimental
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will probably go with @experimental jsdoc annotation right ?

**For stable packages (v9 and later):**

- All stable APIs have clean names without instability markers
- Internal APIs shouldn't be exported; use `@internal` JSDoc tag for documentation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like good time to open again lint rule implementation for no-annotate.

we could also approach this the other way around -> only @public annotated apis can be exported

  • this can be checked already by api extractor and simple failing tool could be written to check this

question is how to properly decouple experimental things to not be used "by accident" in stable apis, which would probably trigger chain of issues when "removing" these experimental ones in next major

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: RFC Request for Feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants