Backstage New Frontend System - Comprehensive Guide
Version: Backstage v1.42.0+ Status: Complete Reference Documentation Last Updated: 2025-10-27
Overviewโ
This documentation provides a comprehensive guide to Backstage's New Frontend System, an extension-based architecture that replaces the legacy frontend system. It includes practical examples, patterns, and best practices for building plugins and applications.
Purposeโ
- Developer Guide: Help developers build plugins and apps with the new frontend system
- Migration Reference: Assist teams migrating from legacy to new frontend system
- Practical Examples: Working code examples for common patterns and use cases
- Best Practices: Extract patterns from Backstage core and community plugins
Key Benefits of the New Frontend Systemโ
- Extension-Based Architecture: Modular, composable, and declarative
- Automatic Plugin Discovery: Install plugins via
package.json, no manual imports - Configuration-Driven: Override extensions via
app-config.yaml - Better Separation of Concerns: Clear boundaries between plugins, extensions, and APIs
- Type-Safe: Strong TypeScript support throughout
๐ Documentation Structureโ
Core Conceptsโ
-
Architecture Overview โญ START HERE
- Extension tree architecture
- Building blocks (App, Extensions, Plugins, Utility APIs)
- Data flow and extension inputs/outputs
- Comparison with legacy system
-
- Creating apps with
createApp() - Feature discovery and installation
- Plugin info resolution
- App configuration patterns
- Creating apps with
-
- Extension structure (ID, inputs, outputs, attachment points)
- Creating extensions with
createExtension() - Extension data references
- Extension blueprints (PageBlueprint, ApiBlueprint, etc.)
- Configuration schemas and factories
-
- What are Utility APIs?
- Creating API refs and implementations
- Dependencies between APIs
- Consuming APIs in components and extensions
-
- Standard auth API refs (GitHub, GitLab, OIDC, OAuth2)
- How OAuth2.create() works
- Frontend/backend separation
- Registering custom auth providers
- API factory patterns
- OIDC and PKCE implementation
-
- Plugin structure in new frontend system
- Alpha exports (
/alpha) - Creating frontend plugins with
createFrontendPlugin() - Providing extensions from plugins
- Plugin-to-plugin communication
-
- Legacy vs New frontend system
- Phase 1: Hybrid configuration
- Phase 2: Complete transition
- Migrating specific components (SignInPage, Sidebar, Routes)
- Troubleshooting common issues
๐ก Practical Examplesโ
All code examples are extracted from Backstage core and tested patterns:
App Creation Examplesโ
examples/app-creation/basic-app.tsx- Minimal app setupexamples/app-creation/feature-discovery.yaml- Automatic plugin discoveryexamples/app-creation/plugin-overrides.yaml- Override plugin info
Extension Examplesโ
examples/extensions/simple-extension.tsx- Basic extensionexamples/extensions/extension-with-inputs.tsx- Parent/child extensionsexamples/extensions/extension-with-config.tsx- Configuration schemaexamples/extensions/page-blueprint.tsx- Using PageBlueprint
Utility API Examplesโ
examples/utility-apis/creating-api-ref.ts- Define API contractexamples/utility-apis/api-implementation.tsx- Implement and register APIexamples/utility-apis/consuming-api.tsx- Use API in components
Auth Provider Examplesโ
examples/auth-providers/custom-oidc-ref.ts- Create custom OIDC API refexamples/auth-providers/custom-oidc-implementation.tsx- Implement custom OIDC providerexamples/auth-providers/oauth2-create-pattern.tsx- How OAuth2.create() works
Plugin Examplesโ
examples/plugins/simple-plugin.tsx- Basic plugin with one pageexamples/plugins/plugin-with-api.tsx- Plugin providing utility API
โ Requirements Questions & Answersโ
This section maps all questions from new-frontend-system-deep-dive-requirements.md to their answers in the documentation.
Category 1: Frontend/Backend Separationโ
โ Q1.1: Provider ID Mappingโ
Question: How does the frontend know which backend auth providers are available?
Status: โ ANSWERED
Answer:
- Frontend auth providers are registered independently from backend providers
- No automatic discovery of backend providers by the frontend
- Frontend creates auth API instances using
OAuth2.create()with provider ID - The provider ID must match between frontend API and backend authenticator
- Frontend makes requests to
/api/auth/{provider}/startusing the configured provider ID - Backend responds based on registered provider routes
Documentation: See 05-auth-providers.md ยง Frontend/Backend Separation
Example: examples/auth-providers/frontend-backend-matching.tsx
โ Q1.2: OAuth2 Generic Implementationโ
Question: Is the OAuth2.create() implementation generic enough to work with any backend provider by name?
Status: โ ANSWERED
Answer:
- YES,
OAuth2.create()is completely generic and provider-agnostic - It only needs: configApi, discoveryApi, oauthRequestApi, and a provider ID
- The same OAuth2 class handles all OAuth2/OIDC flows (GitHub, Google, Okta, custom OIDC, etc.)
- Provider-specific logic is backend-only (scopes, client credentials, PKCE, etc.)
- Frontend only handles: popup flow, token storage, refresh logic
Documentation: See 05-auth-providers.md ยง OAuth2.create() Deep Dive
Example: examples/auth-providers/oauth2-create-pattern.tsx
โ Q1.3: PKCE Transparencyโ
Question: Is PKCE completely transparent to the frontend, handled entirely by the backend?
Status: โ ANSWERED
Answer:
- YES, PKCE is 100% backend-transparent to the frontend
- Frontend code is identical for PKCE vs client secret flows
code_challengeandcode_verifierare generated and handled by backend only- Frontend only sees: standard OAuth2 authorization code flow
- This confirms the hypothesis: zero custom frontend code needed for PKCE
Documentation: See 05-auth-providers.md ยง PKCE and Frontend Transparency
Key Insight: You can use the standard oidcAuthApiRef (or create a generic one) with a custom PKCE backend, requiring no custom frontend auth code.
Category 2: Standard Auth Provider API Referencesโ
โ Q2.1: OIDC Auth API Referenceโ
Question: Does Backstage core provide a standard oidcAuthApiRef?
Status: โ ๏ธ PARTIALLY ANSWERED
Answer:
- NO standard
oidcAuthApiRefexported from core packages (as of investigation) - However, provider-specific refs exist:
oktaAuthApiRef,googleAuthApiRef,microsoftAuthApiRef, etc. - These all implement
OAuthApi,OpenIdConnectApi,ProfileInfoApi,BackstageIdentityApi, andSessionApi - You can create your own generic
oidcAuthApiRefusing the same pattern - Or use a provider-specific ref (e.g.,
oktaAuthApiRef) even if your backend is custom OIDC
Documentation: See 05-auth-providers.md ยง Standard Auth API Refs
Example: examples/auth-providers/custom-oidc-ref.ts
โ Q2.2: Generic OAuth2 API Referenceโ
Question: Is there a generic oauth2AuthApiRef that works with any OAuth2-compatible provider?
Status: โ ANSWERED
Answer:
- NO generic
oauth2AuthApiRefexported, but easy to create - All standard providers (GitHub, Google, Okta, etc.) use
OAuth2.create()internally - Pattern: Create custom API ref + use
OAuth2.create()with your provider ID - This is the recommended approach for custom OAuth2/OIDC providers
Documentation: See 05-auth-providers.md ยง Creating Custom Auth API Refs
Example: examples/auth-providers/generic-oauth2-ref.ts
Category 3: How Standard Providers Workโ
โ Q3.1: GitHub Auth Registrationโ
Question: How is githubAuthApiRef registered and made available in the New Frontend System?
Status: โ ANSWERED
Answer:
- Standard providers are registered in
@backstage/frontend-defaults - They are automatically available when using
createApp()from@backstage/frontend-defaults - Registration happens via API extensions created with
ApiBlueprint - Extensions attach to
coreextension'sapisinput - No manual registration needed for standard providers (GitHub, Google, etc.)
Documentation: See 05-auth-providers.md ยง How Standard Providers Are Registered
File Reference: backstage/packages/frontend-defaults/src/ (see investigation report)
โ Q3.2: Default API Factoriesโ
Question: Does @backstage/frontend-defaults automatically register API factories for standard auth providers?
Status: โ ANSWERED
Answer:
- YES,
@backstage/frontend-defaultsincludes default API factories - Standard auth providers (GitHub, Google, Okta, etc.) are pre-registered
- Also includes: configApi, discoveryApi, storageApi, errorApi, and more
- This is why GitHub auth works "out of the box" without explicit registration
- Custom auth providers must be registered manually using
ApiBlueprint
Documentation: See 04-utility-apis.md ยง Default Utility APIs
Category 4: New Frontend System Extension Pointsโ
โ Q4.1: API Registration Extension Pointโ
Question: What is the correct extension point for registering custom API implementations?
Status: โ ANSWERED
Answer:
- Use
ApiBlueprint.make()to create API extensions - API extensions attach to
coreextension'sapisinput automatically (handled by blueprint) - Register via
createFrontendModule()and add to app'sfeaturesarray - Pattern:
const myApi = ApiBlueprint.make({
name: 'my-api',
params: {
api: myApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) => new MyApiImpl({ configApi }),
},
});
const myModule = createFrontendModule({
pluginId: 'app',
extensions: [myApi],
});
createApp({ features: [myModule] });
Documentation: See 04-utility-apis.md ยง Registering Custom APIs
Example: examples/utility-apis/api-registration-complete.tsx
โ Q4.2: Extension Data Types for APIsโ
Question: What is the correct way to use coreExtensionData for API factories?
Status: โ ANSWERED
Answer:
- Don't use
coreExtensionData.apiFactorydirectly when using blueprints ApiBlueprinthandles all extension data internally- If using
createExtension()directly (not recommended for APIs):- Import
apiFactoryDataReffrom@backstage/frontend-plugin-api - Return
[apiFactoryDataRef(factory)]from factory function
- Import
- Recommendation: Always use
ApiBlueprint.make()for APIs
Documentation: See 03-extensions.md ยง Extension Data References
โ Q4.3: ApiBlueprint vs createExtensionโ
Question: When should we use ApiBlueprint.make() vs createExtension() for API registration?
Status: โ ANSWERED
Answer:
- ALWAYS use
ApiBlueprint.make()for Utility APIs createExtension()is low-level and requires manual extension data handlingApiBlueprintprovides:- Correct attachment point (to
core/apis) - Proper extension data output (apiFactoryDataRef)
- Type safety and validation
- Consistent naming patterns
- Correct attachment point (to
createExtension()is for advanced custom extension types only
Documentation: See 04-utility-apis.md ยง API Blueprints vs createExtension
Category 5: Custom Auth Provider Supportโ
โ Q5.1: Custom Provider Support Statusโ
Question: Are custom auth providers officially supported in New Frontend System v1.42.0+?
Status: โ ANSWERED
Answer:
- YES, fully supported via
ApiBlueprintpattern - Same mechanism used internally for standard providers
- Well-documented pattern (though scattered across docs)
- Production-ready and stable
- Recommended approach:
ApiBlueprint.make()+OAuth2.create()
Documentation: See 05-auth-providers.md ยง Custom Provider Support
โ Q5.2: Provider Override Patternโ
Question: Can a custom backend module override a standard provider?
Status: โ ANSWERED
Answer:
- YES, through extension overrides
- Frontend: Create API extension with same ID as standard provider
- Backend: Register backend module with same provider ID
- Last-registered extension wins (frontend), modules extend backend
- Useful for: customizing GitHub scope, adding PKCE to OIDC, etc.
Documentation: See 05-auth-providers.md ยง Overriding Standard Providers
Example: examples/auth-providers/override-github-scopes.tsx
###Category 6: Migration Patterns
โ Q6.1: Legacy vs New Frontend Comparisonโ
Question: What changed in auth provider registration between Legacy and New Frontend Systems?
Status: โ ANSWERED
Answer:
| Aspect | Legacy Frontend System | New Frontend System |
|---|---|---|
| Registration | createApiFactory() in apis.ts | ApiBlueprint.make() in module |
| Installation | Pass to createApp({ apis: [...] }) | Pass to createApp({ features: [module] }) |
| Location | packages/app/src/apis.ts | packages/app/src/modules/ or plugin |
| Discovery | Manual import required | Can use automatic discovery |
| Override | Replace in apis array | Extension override or feature order |
| Configuration | Code only | Can use app-config.yaml |
Documentation: See 07-migration.md ยง Migrating Auth Providers
Example: examples/auth-providers/legacy-vs-new-comparison.tsx
โ Q6.2: Missing Migration Documentationโ
Question: Is there migration documentation for custom auth providers specifically?
Status: โ ๏ธ PARTIALLY ANSWERED
Answer:
- Limited official migration docs for custom auth providers
- General migration guide covers API factories โ ApiBlueprint pattern
- No specific "OIDC with PKCE" migration guide
- This documentation fills that gap
- Official docs focus on standard providers (GitHub, Google, etc.)
Documentation: This guide serves as the missing documentation
See: 07-migration.md ยง Auth Provider Migration Details
๐ฏ Key Takeawaysโ
1. Extension-Based Architectureโ
- Everything is an Extension: Apps, plugins, pages, APIs, themes
- Tree Structure: Extensions form a hierarchical tree
- Configuration-Driven: Override behavior via app-config.yaml without code changes
2. Simplified Developmentโ
-
Blueprints: Pre-built patterns for common extension types
PageBlueprintfor pagesApiBlueprintfor utility APIsSignInPageBlueprintfor sign-in pagesThemeBlueprintfor themes
-
Feature Discovery: Auto-discover plugins from package.json
- Add plugin to dependencies
- Enable
app.packages: allin config - No manual imports needed
3. Clean Separation of Concernsโ
- Frontend/Backend Independence: Clear boundaries between layers
- Type Safety: Strong TypeScript support throughout
- Testability: Easy to mock and test components
- Modularity: Plugins are self-contained and reusable
4. Migration Pathโ
- Hybrid Mode: Run both systems side-by-side during migration
- Incremental: Migrate one plugin at a time
- Backward Compatible: Plugins can support both systems
๐ Additional Resourcesโ
Backstage Official Docsโ
Source Code Referenceโ
- Core Frontend Packages:
backstage/packages/frontend-* - Core Auth Implementation:
backstage/packages/core-app-api/src/apis/implementations/auth/ - Frontend Defaults:
backstage/packages/frontend-defaults/ - Auth Backend:
backstage/plugins/auth-backend/ - OIDC Provider Module:
backstage/plugins/auth-backend-module-oidc-provider/
Community Resourcesโ
- Backstage Discord - #support channel
- GitHub Discussions
- GitHub Issues
๐งช Testing Examplesโ
Running Examples Locallyโ
All examples can be tested by:
- Creating a new Backstage app with
npx @backstage/create-app --next - Copying example code into appropriate files
- Running
yarn devto test
Example Docker Setup (Bonus)โ
For quickly testing examples:
# Build a test image with Backstage v1.42.0+
docker build -t backstage-test -f Dockerfile.test .
# Run with example mounted
docker run -it -v $(pwd)/examples:/app/examples backstage-test
# Inside container
cd /app && yarn dev
See examples/README.md for Docker setup details.
๐ค Contributingโ
Found an error or want to improve the documentation?
- Check existing issues: GitHub Issues
- Create a PR with your changes
- Update the requirements tracking if you answer new questions
๐ Document Maintenanceโ
- Created: 2025-10-27
- Backstage Version: v1.42.0+
- Status: Complete
- Next Review: When Backstage releases major frontend system changes
Navigation: