npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@stackgenhq/backstage-plugin-stackgen-backend

v0.3.8

Published

StackGen Backstage backend plugin — scaffolder actions, UI proxies, templates

Downloads

328

Readme

Backstage Plugin StackGen Backend

Published to npmjs.org as @stackgenhq/backstage-plugin-stackgen-backend. Install works without a GitHub PAT. Release process: docs/PUBLISH.md.

Installation

This plugin is installed via the @stackgenhq/backstage-plugin-stackgen-backend package. To install it to your backend package, run the following command:

# From your root directory
yarn --cwd packages/backend add @stackgenhq/backstage-plugin-stackgen-backend

No .yarnrc.yml GitHub Packages scope is required if you install from npmjs. The same version is also published to GitHub Packages. Then add the plugin to your backend in packages/backend/src/index.ts:

const backend = createBackend();
// ...
backend.add(import('@stackgenhq/backstage-plugin-stackgen-backend'));

add configuration required for plugin in backstage app-config.yaml

stackGen:
  # The base URL for the StackGen API. Default: `https://cloud.stackgen.com`
  baseUrl: "${BACKSTAGE_ADAPTER_URL}"
  apiToken: "${STACKGEN_PAT}"
  # Optional: role assigned when createAppStack auto-adds PAT user to project
  # Defaults to admin role 00000000-0000-0000-0000-000000000002
  projectMemberRoleId: "${STACKGEN_PROJECT_MEMBER_ROLE_ID}"
  # Preferred allowlist of project UUIDs (comma-separated). Alias: allowedTeams
  allowedProjects: ""
  # Optional default project scope. Alias: orgId
  # projectId: ""

allowedProjects is optional; by default all projects the STACKGEN_PAT can access are available. Restrict access by listing project UUIDs. Deprecated alias: allowedTeams (same comma-separated list).

stackGen:
  baseUrl: "${BACKSTAGE_ADAPTER_URL}" 
  apiToken: "${STACKGEN_PAT}"
  allowedProjects: "20f0e211-15ce-4d2c-1e12-0555bffee7bd,20f0e211-15ce-4d2c-2e22-0555bffee7bd"

API specification

The canonical Integrations Gateway API spec is maintained in the integrations repo:

https://github.com/appcd-dev/integrations/blob/main/api-docs/api-spec.yml

Use that spec as the source of truth for request/response schemas and endpoints. This plugin is not generated from the spec; implementation is in code and may be updated independently.

Compatibility

| Package | Tested / required notes | |---------|-------------------------| | @backstage/plugin-scaffolder-node | Declared dependency ^0.12.5 (tested). Schema declarations use the function form (schema.input: () => zodObject or (z) => z.object(…)) required by parseSchemas. Do not pass raw ZodObject instances — modern scaffolder-node ignores them and leaves schema.input / schema.output undefined. Older scaffolder-node 0.6.x accepted raw Zod objects via safeParseAsync detection; that path is obsolete. | | Node.js | >=20 |

ENG-3394: Releases ≤0.3.2 (built against scaffolder-node 0.6.x with raw ZodObject schemas) show blank input fields on Backstage “Installed actions” when paired with scaffolder-node ≥0.8 (including 0.12.5) and skip scaffolder upfront validation. Fixed in 0.3.3 (package track 0.3.3-beta.3+): function-form schemas + scaffolder-node ^0.12.5.

Available Actions

Setup

To use these actions, add the following code in your backend in packages/backend/src/index.ts:

import { createAppStackAction, createProjectAction, downloadIaCAction, exportAppStackToGitAction } from '@stackgenhq/backstage-plugin-stackgen-backend';
import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node';
import { coreServices, createBackendModule } from '@backstage/backend-plugin-api';

...

export const scaffolderCustomExtension = createBackendModule({
  pluginId: 'scaffolder',
  moduleId: 'custom-extensions',
  register(env) {
    env.registerInit({
      deps: {
        scaffolder: scaffolderActionsExtensionPoint,
        config: coreServices.rootConfig,
        logger: coreServices.logger,
      },
      async init({ scaffolder, config, logger }) {
        scaffolder.addActions(
          createProjectAction(config, logger),
          createAppStackAction(config, logger),
          downloadIaCAction(config, logger),
          exportAppStackToGitAction(config, logger),
          // ...other actions
        );
      },
    });
  },
});

...

backend.add(scaffolderCustomExtension);

stackGen:createProject

Creates a Project in StackGen with optional git and environment configuration.

A StackGen project is identified by projectId (UUID). After creation, pass projectId to stackGen:createAppStack as appstack.projectId. Deprecated output alias: teamId (same UUID).

Inputs:

| Field | Type | Required | Description | |-------|------|----------|-------------| | project.name | string | yes | Project name | | project.description | string | yes | Project description | | project.gitConfig | object | no | Default git configuration (scmType, repoUrl, targetBranch, path, vaultReference) | | project.environmentConfig | object | no | Default environment configuration (templates, variables, overrides) |

Outputs:

| Field | Type | Description | |-------|------|-------------| | projectId | string | UUID of the created project | | projectName | string | Name of the project | | teamId | string | Deprecated alias of projectId (same UUID) | | alreadyExisted | boolean | true if a project with this name already existed (409), false if newly created (201) |

Status code handling:

  • 201 -- Project created. Outputs projectId, projectName, teamId (alias), alreadyExisted: false.
  • 409 -- Project already exists. Treated as success. Outputs projectId, projectName, teamId (alias), alreadyExisted: true.
  • 403 -- Throws error: invalid token permissions.
  • 400 -- Throws error: invalid project name.

Important behavior for project initialization:

  • Auxiliary initialization settings (for example environment templates, variables, overrides, default configs like gitConfig/environmentConfig) are only applied when the plugin actually creates a new project.
  • If the requested project already exists (409 path), the action returns that project identifiers and proceeds, but it does not patch/update the existing project with those extra settings.
  • Updating existing projects with those parameters is planned for a future update.

Example:

steps:
  - id: create-project
    name: Create StackGen Project
    action: stackGen:createProject
    input:
      project:
        name: ${{ parameters.projectName }}
        description: "Project created via Backstage"

Example with git and environment config:

steps:
  - id: create-project
    name: Create StackGen Project
    action: stackGen:createProject
    input:
      project:
        name: ${{ parameters.projectName }}
        description: "Project created via Backstage"
        gitConfig:
          name: "default-git-config"
          type: "git"
          parameters:
            scmType: "GITHUB"
            repoUrl: "https://github.com/org/repo.git"
            targetBranch: "main"
          vaultReference: "550e8400-e29b-41d4-a716-446655440000"
          default: true
        environmentConfig:
          name: "default-env-config"
          environmentTemplates:
            - name: "production"
              color: "#FF0000"
              stateBackendTemplate:
                type: "S3"
                configJson: '{"bucket": "my-terraform-state"}'
          variables:
            - name: "region"
              type: "string"
              defaultValueJson: '"us-east-1"'
              description: "AWS region for deployment"
          variableOverrides:
            - variableName: "region"
              environmentTemplateName: "production"
              valueJson: '"us-west-2"'

Environment variable value types (defaultValueJson and valueJson):

  • These fields are JSON literals encoded as strings in YAML.
  • The plugin passes them through to StackGen, so you can use non-string JSON values.
  • Set variables[].type to match your intended semantic type in StackGen.

Examples:

variables:
  - name: "region"
    type: "string"
    defaultValueJson: '"us-east-1"'
  - name: "replicas"
    type: "number"
    defaultValueJson: '3'
  - name: "enableAutoscaling"
    type: "boolean"
    defaultValueJson: 'true'
  - name: "subnetIds"
    type: "list"
    defaultValueJson: '["subnet-1","subnet-2"]'
  - name: "extraTags"
    type: "object"
    defaultValueJson: '{"team":"platform","env":"dev"}'

variableOverrides:
  - variableName: "replicas"
    environmentTemplateName: "prod"
    valueJson: '5'

stackGen:createAppStack

Creates an AppStack in StackGen for a given project with specified resources and configurations.

Behavior by input type:

  • Before appstack creation: action resolves the PAT user via GET /appcd/api/v1/auth/me and attempts to assign that user to the target project (appstack.projectId) via POST /appcd/api/v1/orgs/{projectId}/users using role projectMemberRoleId (default admin). If this preflight assignment fails, appstack creation still proceeds and the membership error is logged as a warning—this usually happens if the PAT user was already a member of the project. If the PAT was newly added, it stays a project member after the action completes (no automatic removal).
  • When no resourcePackId is present: uses the legacy create path POST /stackgen/v1/appstacks with payload shape name, coreConfig (provider, targetCompute), resources, and team/project id.
  • When templateAppstackId is set (and resources is empty): loads the source AppStack via GET /appcd/api/v1/appstacks/{uuid}, creates a blank appstack through integrations, then clones topology with POST /iac-gen/v1/topologies?orgId=… (appstackRefId). Deployment type and IaC type come from the source coreConfig (defaults: k8s, Terraform if missing).
  • When any resourcePackId is present: uses a two-step integrations-compatible flow:
    1. Create a blank appstack via POST /integrations/api/v1/projects/{projectId}/appstacks (empty topology)
    2. Add each resource pack into that topology via POST /iac-gen/v1/topologies/{topologyId}/resources?orgId={orgScope}, preserving resourcePackId semantics.

Inputs:

| Field | Type | Required | Description | |-------|------|----------|-------------| | appstack.name or appstack.appstackName | string | yes | AppStack name | | appstack.projectId | string | yes | Project UUID (use projectId output from stackGen:createProject). Deprecated alias: appstack.teamId | | appstack.cloudProvider | string | conditional | Required unless templateAppstackId is set (then read from appcd coreConfig.provider) | | appstack.templateAppstackId | string (UUID) | no | If set: load source AppStack from appcd, then clone topology via iac-gen (appstackRefId). Cannot be used with a non-empty resources array | | appstack.resources | array | yes | List of resources (can be empty []) |

Integrations POST …/appstacks only accepts name, cloudProvider, and topology (no extra metadata fields).

Each resource in the array:

| Field | Type | Required | Description | |-------|------|----------|-------------| | resourceType | string | yes | Valid StackGen resource type | | configuration | object | no | Resource configuration (mutually exclusive with resourcePackId) | | tfVars | object | no | Terraform variables | | resourcePackId | string | no | Resource pack ID (mutually exclusive with configuration) | | children | array | no | Child resources for group resource types |

Outputs:

| Field | Type | Description | |-------|------|-------------| | appstackId | string | UUID of the created appstack | | appstackName | string | Name of the created appstack | | appStackURL | string | Direct URL to the created appstack in StackGen |

Example (chained with project creation):

steps:
  - id: create-project
    name: Create StackGen Project
    action: stackGen:createProject
    input:
      project:
        name: ${{ parameters.projectName }}
        description: "Project created via Backstage"

  - id: stackGen
    name: Create AppStack
    action: stackGen:createAppStack
    input:
      appstack:
        name: "MyAppStack"
        projectId: ${{ steps['create-project'].output.projectId }}
        cloudProvider: "aws"
        resources:
          - resourceType: "aws_s3"
            # Only one of 'configuration' or 'resourcePackId' should be provided
            configuration:
              bucket_name: "mybucket"
          - resourceType: "resourcePack"
            resourcePackId: "20f0e212-15ce-4d2c-1e12-0555bffee7bd"
            # No configuration here because resourcePackId is used (legacy path preserves resourcePackId)
          - resourceType: "helm_workload"
            children:
              - resourceType: "helm_workload"
                configuration:
                  name: test-workload
                  image: test-image
              - resourceType: helm_service
                configuration:
                  name: test-service

Example output:

output:
  links:
    - title: 'View Created AppStack in StackGen'
      url: '${{ steps.stackGen.output.appStackURL }}'

Example templates walkthrough

The templates in examples/template/ demonstrate end-to-end StackGen scaffolding flows:

| Template | Description | |----------|-------------| | stackgen-export-iac | Manually fetch IaC from an AppStack and push it to GitHub via Backstage — useful when you prefer Backstage to handle the git push instead of StackGen's native git integration. | | stackgen-appstack-with-resources | Creates a project with environments, then an AppStack with a resource pack, standalone S3 bucket, and custom Terraform module (via templateId). | | stackgen-full-setup | The most comprehensive template: project + Git config + AppStack (resource pack + S3 + custom module) + production/staging environments with per-environment TF variables + S3 state backends. | | stackgen-project-basic | Creates an empty project — a blank starting point. | | stackgen-project-advanced | Creates a project with Git integration, environments, variables, and per-environment overrides. |

Project initialization in these templates can include:

  • Environment templates (for example dev, stage, prod).
  • Default variables and per-environment variable overrides.
  • Git configuration via project.gitConfig.
  • Per-environment storage backend configuration via stateBackendTemplate.

Disabling the Frontend Plugin

The StackGen plugin includes an optional frontend component that adds a "StackGen" item to the Backstage sidebar. If you only need the backend scaffolder actions (templates) and don't want the sidebar entry, you can toggle it off by commenting out two lines:

1. Remove the sidebar item in packages/app/src/components/Root/Root.tsx:

// Comment out this line:
{/* <SidebarItem icon={StackGenIcon} to="stackgen" text="StackGen"/> */}

2. Remove the route in packages/app/src/App.tsx:

// Comment out this line:
{/* <Route path="/stackgen" element={<StackGenPage />} /> */}

The imports can remain in place — they'll be unused but won't cause errors. To re-enable the frontend later, simply uncomment both lines and restart Backstage.

stackGen:downloadIaC

This action downloads and extracts the Infrastructure as Code (IaC) files for a specified AppStack from StackGen.

Example input:

steps:
  - id: download-iac
    name: Download IaC
    action: stackGen:downloadIaC
    input:
      appstackName: "MyAppStack"
      projectId: "project-uuid"
      # Deprecated alias: teamId
      # Optional: path where IaC files should be extracted, defaults to "./"
      extractedIaCPath: "./infrastructure"

stackGen:exportToGit

This action is a compatibility wrapper over the new stack-exporter flow. It resolves topology for projectId + appstackName, selects an existing git exporter config for the project (or uses an explicit id), and triggers exporter POST /export.

Inputs (high level)

| Field | Required | Description | |-------|----------|-------------| | appstackName, projectId | yes | AppStack and project id (teamId deprecated alias) | | configId | no | When set (non-empty), used as stack-exporter git config_id; skips listing, chooseConfig, and bootstrap. Precedence: configId overrides gitConfig. In Software Templates, map from the frontend field existingExporterConfigId (ExporterGitConfigSelect). | | topologyId, appstackId | no | Optional topology / appstack hints for resolution | | gitConfig | no | Bootstrap shape (same as createProject.project.gitConfig). Ignored when configId is set. | | baseBranch | no | Branch to base the change on (PR base / commit destination). Maps to the exporter target_branch override. Blank uses the git config default. Prefill via ExporterBaseBranch. | | pushBranch | no | Branch StackGen pushes the generated IaC to (source/head branch). Maps to the exporter branch_format override. Blank creates a new one. Prefill via ExporterPushBranch.branch. | | useSameBranch | no | When true, sets exporter use_same_branch=true (reuse previous export head). Set by ExporterPushBranch when the history suggestion is left unchanged. | | createPr | no | Boolean, default true. When false, changes are committed directly to the branch without opening a PR (exporter commit_only). | | overrides | no | Raw exporter overrides (e.g. pr_title, commit_msg). An explicit entry wins over the derived key for the same override. |

These give the Backstage plugin parity with the StackGen UI git export (base branch, push branch, create PR). baseBranch, pushBranch, useSameBranch, and createPr are translated to exporter override keys in one place (buildExportOverrides), so templates do not need to know the internal keys.

Outputs

| Field | When present | Description | |-------|--------------|-------------| | pullRequestUrl, externalLink | PR created (createPr true) | URL of the opened pull request | | committedBranch | commit-only (createPr false) | Branch StackGen committed the changes to | | notes | always (when returned) | Human-readable export notes (e.g. "committed to branch X") |

A commit-only export (createPr: false) does not open a pull request, so pullRequestUrl is absent; use committedBranch / notes in that case.

Notes:

  • Explicit configId: Use when the user picks a config in Backstage (ExporterGitConfigSelect writes the config uuid to existingExporterConfigId; pass it as configId in the action input). Precedence: configId overrides gitConfig.
  • Listing configs: If configId and gitConfig are omitted, GET .../exporter/.../config?orgId={projectId}&type=git&appstackId={appstackId} — if a single/default git config exists for that AppStack, it is used for POST .../export. Multiple configs require configId.
  • Bootstrap (no git config for the AppStack yet): Project-level gitConfig from stackGen:createProject is stored as stack-exporter templates (GET .../exporter/.../config/template?orgId={projectId}). When the list step finds nothing usable, this action loads that template and POST .../exporter/.../config?orgId={projectId} with appstack_id so the config is scoped to the AppStack.
  • Optional gitConfig on this action: Same shape as createProject.project.gitConfig. When provided (and configId is not set), creates a new appstack-scoped config from that input and uses it. Not used when configId is set.
  • appstackId: Optional. When omitted, resolved from projectId + appstackName via appcd GET /appstacks (appstackId for exporter binding, uuid for topology).

Example input:

  steps:
    - id: exportToGit
      name: Export AppStack to Git via StackGen
      action: stackGen:exportToGit
      input:
        appstackName: ${{ parameters.appstackName }}
        projectId: ${{ parameters.projectId }}
        # Optional: explicit exporter git config (from ExporterGitConfigSelect → existingExporterConfigId)
        configId: ${{ parameters.existingExporterConfigId }}
        # gitConfig omitted: uses project template from createProject when no appstack config exists
        # First-class git export controls (parity with the StackGen UI):
        baseBranch: ${{ parameters.baseBranch }}   # PR base / commit destination (target_branch)
        pushBranch: ${{ parameters.pushBranch.branch }}   # branch StackGen pushes to (branch_format)
        useSameBranch: ${{ parameters.pushBranch.useSameBranch }}  # reuse history head when unchanged
        createPr: ${{ parameters.createPr }}       # false => commit_only (no PR)
        overrides:
          - key: pr_title
            value: Export IaC from Backstage
          - key: commit_msg
            value: chore: export iac

Example output:

output:
  links:
    - title: 'Pull Request'
      url: '${{ steps.exportToGit.output.pullRequestUrl }}'

Development

Use the stackgen-backstage app to run Backstage with your local backend plugin build.

  1. Lay out repositories so the backend plugin and the Backstage app are siblings (adjust paths below if yours differ):

    <workspace>/
      stackgen-backstage/
      backstage-plugin-stackgen-backend/
  2. Point the backend at your local plugin in stackgen-backstage/packages/backend/package.json:

    Set the dependency to a Yarn link relative to packages/backend (three levels up to the parent of stackgen-backstage, then into the backend plugin repo):

    "@stackgenhq/backstage-plugin-stackgen-backend": "link:../../../backstage-plugin-stackgen-backend"

    If your clone lives elsewhere, change the link: path accordingly (it must resolve from packages/backend to the root of backstage-plugin-stackgen-backend).

  3. Build the backend plugin:

    yarn install
    yarn tsc && yarn build
  4. Install and run stackgen-backstage from the Backstage repo root:

    yarn install

    Configure app-config.yaml (or local overrides) with stackGen.baseUrl, stackGen.apiToken, and any optional keys you need (see Installation). The stackgen-backstage README also documents env vars such as STACKGEN_API_TOKEN if you wire config that way.

  5. Start the app (frontend + backend in parallel):

    yarn dev

    Alternatively, run workspaces separately: yarn start-backend and yarn start (app only), as described in the stackgen-backstage package.json scripts.

  6. After backend plugin code changes, rebuild the plugin (yarn tsc && yarn build in backstage-plugin-stackgen-backend), then install the dependencies again.