# Integrating Backstage Scaffolder with Custom Plugins and Kubernetes Operators Backstage's Scaffolder provides powerful capabilities for automating resource creation and integrating with custom plugins and Kubernetes operators. This comprehensive guide covers best practices, implementation patterns, and real-world examples across 10 key integration areas. ## Best practices for integrating custom Backstage plugins The modern approach to integrating custom plugins with Scaffolder leverages Backstage's new backend module system through extension points. This architecture provides clean separation of concerns and better maintainability. **Implementation Architecture**: Custom plugins integrate with Scaffolder through the `scaffolderActionsExtensionPoint`, allowing them to register custom actions that templates can invoke. The recommended pattern uses backend modules rather than direct plugin integration: ```typescript export const scaffolderModule = createBackendModule({ moduleId: 'custom-action', pluginId: 'scaffolder', register({ registerInit }) { registerInit({ deps: { scaffolderActions: scaffolderActionsExtensionPoint, }, async init({ scaffolderActions }) { scaffolderActions.addActions(createCustomAction()); }, }); }, }); ``` Key integration principles include namespace actions to avoid collisions (using patterns like `acme:ping`), implementing proper error handling and logging, and leveraging Backstage's dependency injection system for shared services. While no specific "tollgate payment plugin" examples were found in the ecosystem, the patterns apply universally to any payment validation plugin. ## Creating custom Scaffolder actions for Kubernetes operators Custom Scaffolder actions enable direct interaction with Kubernetes operators and Custom Resources through the `createTemplateAction` API. The implementation requires careful consideration of cluster configuration, authentication, and error handling. **Action Structure and Registration**: Create actions that handle Kubernetes manifests including CRDs: ```typescript export const createKubernetesApplyAction = () => { return createTemplateAction<{ manifest: string; namespaced: boolean; clusterName?: string; }>({ id: 'kubernetes:apply', description: 'Apply Kubernetes manifests including Custom Resources', schema: { input: { required: ['manifest'], type: 'object', properties: { manifest: { type: 'string' }, namespaced: { type: 'boolean', default: true }, clusterName: { type: 'string' } } } }, async handler(ctx) { // Apply manifest to cluster // Handle Custom Resources through operator APIs } }); }; ``` The community provides production-ready solutions like `@muvaf/kubernetes-apply` for server-side apply operations, `@devangelista/backstage-scaffolder-kubernetes` for comprehensive Kubernetes operations, and `@janus-idp/backstage-scaffolder-backend-module-kubernetes` as an enterprise-ready module. ## Implementing pricing and cost preview workflows Integrating cost preview and payment validation into Scaffolder workflows represents an emerging pattern combining FinOps practices with self-service infrastructure provisioning. Organizations implement this through custom actions that calculate costs before resource creation. **Cost Estimation Pattern**: Templates can incorporate pre-provisioning cost calculations and approval gates: ```yaml steps: - id: calculate-cost name: Calculate Infrastructure Cost action: custom:cost:estimate input: resources: ${{ parameters.resources }} region: ${{ parameters.region }} instanceType: ${{ parameters.instanceType }} - id: cost-approval-gate name: Cost Approval Gate action: custom:approval:cost input: estimatedCost: ${{ steps.calculate-cost.output.monthlyCost }} threshold: 1000 ``` Integration with tools like Infracost enables real-time cost estimation for over 1,100 Terraform resources across major cloud providers. The implementation should consider resource specifications, regional pricing variations, reserved instance discounts, and usage patterns. ## Catalog items as deployment triggers Scaffolder templates are themselves catalog entities (kind: Template) that appear in the `/create` interface. This integration enables sophisticated patterns where catalog items drive deployment workflows. **Template Discovery and Categorization**: Templates use the `spec.type` field for categorization (service, website, library) and can be filtered by type and ownership. Created entities automatically include annotations like `backstage.io/source-template` to track their origin, enabling "create something similar" workflows. The catalog-driven approach supports dynamic template behavior based on existing catalog entity relationships, with templates able to query catalog entities during execution and adapt behavior accordingly. ## Managing resources after initial creation Post-creation resource management leverages Backstage's catalog system for ongoing lifecycle tracking. Created entities maintain references to their source templates and can be updated through various mechanisms. **Update Strategies**: Organizations typically implement: - GitOps workflows where changes are made via pull requests to repository YAML files - Custom entity providers that programmatically update metadata from external sources - API-based bulk update mechanisms for large-scale changes - Event-driven architectures for real-time synchronization The catalog's processing loops continuously handle entity updates, with configurable intervals balancing freshness with system load. Orphan detection automatically identifies entities that lose their source references. ## Kubernetes resource creation examples Real-world implementations demonstrate various patterns for creating Kubernetes resources through operators: ```yaml apiVersion: scaffolder.backstage.io/v1beta3 kind: Template metadata: name: operator-deployment-template spec: steps: - id: create-custom-resource name: Create Custom Resource action: kubernetes:apply input: namespaced: true manifest: | apiVersion: apiextensions.example.com/v1 kind: MyCustomResource metadata: name: ${{ parameters.name }} namespace: ${{ parameters.namespace }} spec: replicas: 3 configuration: enabled: true ``` For GitOps workflows, templates commonly create ArgoCD Application Custom Resources that manage the actual infrastructure deployment, providing declarative configuration management and automated synchronization. ## Payment validation integration patterns Subscription and payment validation typically follows a multi-step pattern within Scaffolder workflows: ```yaml steps: - id: validate-subscription name: Validate User Subscription action: custom:subscription:validate input: userId: ${{ user.entity.metadata.name }} requiredTier: "premium" - id: payment-intent name: Create Payment Intent action: custom:payment:create-intent input: amount: ${{ steps.calculate-cost.output.totalCost }} - id: payment-confirmation name: Wait for Payment Confirmation action: custom:payment:confirm input: paymentIntentId: ${{ steps.payment-intent.output.intentId }} ``` This pattern ensures resources are only provisioned after successful payment processing and subscription validation. ## Dynamic pricing calculation implementation Dynamic pricing requires a sophisticated calculation engine that considers multiple factors: ```typescript export const createDynamicPricingAction = () => { return createTemplateAction<{ resources: ResourceSpec[]; region: string; duration: number; }>({ id: 'custom:pricing:calculate', async handler(ctx) { const { resources, region, duration = 720 } = ctx.input; let totalCost = 0; const breakdown = []; for (const resource of resources) { const pricing = await getPricingForResource( resource.type, resource.specifications, region ); const resourceCost = calculateResourceCost( pricing, resource.quantity, duration ); totalCost += resourceCost; breakdown.push({ resourceType: resource.type, quantity: resource.quantity, unitPrice: pricing.hourlyRate, totalCost: resourceCost }); } ctx.output('totalCost', totalCost); ctx.output('breakdown', breakdown); } }); }; ``` The system should support enterprise discount programs, volume-based pricing tiers, and multi-cloud pricing normalization using standards like FOCUS. ## Pre-creation validation best practices Effective pre-creation validation combines form-level validation with backend checks. The tollgate pattern implements multi-stage approval: ```yaml steps: - id: technical-validation name: Technical Validation Gate action: custom:tollgate:technical - id: cost-validation name: Cost Validation Gate action: custom:tollgate:cost input: estimatedCost: ${{ steps.cost-estimation.output.totalCost }} - id: security-validation name: Security Validation Gate action: custom:tollgate:security ``` Key validation components include automatic approval for costs under threshold, integration with organizational budget tracking, automatic tagging and cost center assignment, and complete audit trails for all provisioning activities. ## Scaffolder vs Orchestrator comparison **Scaffolder** excels at simple, linear resource provisioning with its template-based approach, built-in integration, and mature ecosystem. It's ideal for rapid prototyping and straightforward use cases without additional infrastructure requirements. **Orchestrator** (Red Hat's plugin) provides advanced workflow capabilities through SonataFlow, supporting complex branching, parallel execution, and state persistence. It's better suited for long-running workflows with multiple decision points, human-in-the-loop approvals, and complex resource provisioning scenarios. Choose Scaffolder for quick setup and simple workflows. Choose Orchestrator when you need advanced workflow patterns, state persistence, visual workflow design, or complex orchestration with rollback capabilities. Many organizations benefit from a hybrid approach, using both tools for their respective strengths. ## Conclusion Integrating Backstage Scaffolder with custom plugins and Kubernetes operators requires careful architecture planning and implementation of proper patterns. Success depends on leveraging the extension point system for clean plugin integration, implementing robust error handling and security measures, designing for scalability from the start, and maintaining clear separation between provisioning logic and business rules. Organizations should start with simple integrations and gradually add complexity based on actual requirements, always keeping developer experience at the forefront of design decisions.