feat(docs): RFC to clarify _unstable naming convention for public APIs#35694
feat(docs): RFC to clarify _unstable naming convention for public APIs#35694dmytrokirpa wants to merge 2 commits intomicrosoft:masterfrom
_unstable naming convention for public APIs#35694Conversation
_unstable naming convention for public APIs_unstable naming convention for public APIs
📊 Bundle size report✅ No changes found |
|
Pull request demo site: URL |
docs/react-v9/contributing/rfcs/react-components/convergence/unstable-naming-convention.md
Show resolved
Hide resolved
Hotell
left a comment
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
what I meant:
Scenario 1 🚨:
-
there is
lib-A/sub-app-Athat 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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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'
There was a problem hiding this comment.
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` |
There was a problem hiding this comment.
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/cliwhich 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 |
There was a problem hiding this comment.
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
/experimentalapi 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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
curious what's the opinion about doubling our API surface because of this change
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
Summary
This RFC proposes deprecating and renaming all public API exports with the
_unstablesuffix 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
_unstablesuffix (e.g.,useBadge_unstable,renderBadge_unstable). Despite the naming suggesting volatility, these APIs are:This creates three main issues:
_unstabledoesn't actually mean unstableProposed Solution
Three coordinated changes:
Remove
_unstablesuffix from stable APIsuseBadge_unstable→useBadgerenderBadge_unstable→renderBadgeuseBadgeStyles_unstable→useBadgeStylesMaintain backward compatibility through deprecated re-exports
Reserve
UNSTABLE_prefix (all caps) exclusively for experimental featuresMigration Support
npx @fluentui/codemods v9-remove-unstable-suffixTimeline
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.