# 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.