Blueprint Composition Patterns

Common patterns for composing blueprints, managing package dependencies, and structuring outputs effectively.

Overview

Blueprints compose multiple packages into deployable infrastructure stacks. This page covers proven patterns for structuring those compositions, managing dependencies between packages, and controlling outputs.

For the basics of creating blueprints, see Creating Blueprints. For dynamic expressions within blueprints, see Using expr.

Composition patterns

Layered architecture

Stack packages in layers: infrastructure, platform, then application. Each layer depends on the one below it.

{
  "packages": [
    {
      "name": "@bluebricks/terraform_aws_vpc",
      "id": "infrastructure_vpc"
    },
    {
      "name": "@bluebricks/terraform_aws_subnet",
      "id": "infrastructure_subnet",
      "props": {
        "vpc_id": {
          "value": "Data.infrastructure_vpc.vpc_id"
        }
      }
    },
    {
      "name": "@bluebricks/helm_nginx",
      "id": "platform_nginx",
      "props": {
        "cluster_name": {
          "value": "Data.infrastructure_subnet.cluster_name"
        }
      }
    },
    {
      "name": "@bluebricks/helm_myapp",
      "id": "application_myapp",
      "props": {
        "nginx_endpoint": {
          "value": "Data.platform_nginx.endpoint"
        }
      }
    }
  ]
}

This gives you clear separation of concerns, predictable dependency flow, and easy maintenance.

Hub and spoke

A central package provides shared resources to multiple consumers.

Spoke packages run in parallel since they share the same dependency. This pattern works well for shared networking, centralized databases, or common security groups.

Microservices composition

Each service is a separate package with shared infrastructure dependencies.

Services with no cross-dependency run in parallel. Services that consume another service's output run after their dependency completes.

Environment-specific composition

Use blueprint inputs to configure the same blueprint differently per collection.

Install the same blueprint into different collections with different values:

Dependency management patterns

Explicit dependencies with version pinning

Pin specific package versions for stability and reproducibility.

Conditional dependencies

Use expressions to control package behavior based on configuration. For a full reference on expression syntax, see Using expr.

Output management patterns

Aggregated outputs

Combine outputs from multiple packages into a single blueprint output.

Conditional outputs

Bluebricks only executes components whose outputs are actually needed. Use conditional outputs to control which packages run.

If enable_monitoring is false, the monitoring component is not executed. This follows Bluebricks' output-driven execution model: props flow down, data flows up based on actual requirements.

Structured outputs

Organize outputs into logical groups for clarity.

Best practices

  • Choose packages that complement each other and verify compatibility

  • Minimize dependencies and avoid circular references

  • Use clear, descriptive naming conventions for package IDs

  • Provide sensible defaults for blueprint inputs

  • Test blueprint composition locally before publishing

  • Pin package versions for production blueprints

Anti-patterns to avoid

Circular dependencies

Deep dependency chains

Prefer hub-and-spoke or layered patterns to maximize parallel execution.

Unclear output references

Use descriptive output names that indicate what the value represents.

See also

Last updated

Was this helpful?