Creating Custom Blueprints

In this tutorial, you’ll learn how to create powerful, reusable blueprints that can be shared across your team and customized for different use cases.

Time to complete: 30-45 minutes

Prerequisites:

  • Teabar account
  • Basic YAML knowledge
  • Understanding of your application architecture

Blueprint Fundamentals

A blueprint defines the complete structure of an environment:

# teabar.yaml
name: my-blueprint
version: "1.0"
description: A description of what this blueprint creates

# Parameters that can be customized
parameters:
  env_type:
    type: string
    default: development

# The components that make up the environment
components:
  app:
    image: myapp:latest

# How components are exposed
expose:
  - component: app
    port: 3000

Step 1: Design Your Blueprint

Identify Components

Start by mapping out your application’s components:

┌─────────────────────────────────────────┐
│            Load Balancer                │
└────────────────┬────────────────────────┘

    ┌────────────┴────────────┐
    │                         │
┌───┴───┐                 ┌───┴───┐
│  Web  │                 │  API  │
└───┬───┘                 └───┬───┘
    │                         │
    └────────────┬────────────┘

         ┌───────┴───────┐
         │               │
    ┌────┴────┐    ┌─────┴────┐
    │ Database│    │  Cache   │
    └─────────┘    └──────────┘

Define Parameters

Identify what should be configurable:

ParameterPurposeExample Values
env_typeEnvironment tierdev, staging, prod
replicasScaling1, 3, 5
resourcesResource allocationsmall, medium, large
featuresFeature flagsanalytics, debug

Step 2: Create the Blueprint

# blueprints/full-stack-app.yaml
name: full-stack-app
version: "2.0"
description: Full-stack application with web frontend, API backend, database, and cache

# Define parameters with types, defaults, and validation
parameters:
  env_type:
    type: string
    description: Environment type (affects resource allocation)
    default: development
    enum: [development, staging, production]
    
  app_version:
    type: string
    description: Application version tag
    default: latest
    
  replicas:
    type: integer
    description: Number of app replicas
    default: 1
    min: 1
    max: 10
    
  enable_monitoring:
    type: boolean
    description: Enable Prometheus metrics collection
    default: false
    
  database_size:
    type: string
    description: Database storage size
    default: 10Gi
    pattern: "^[0-9]+Gi$"

# Resource presets based on env_type
presets:
  development:
    cpu: 1
    memory: 2G
  staging:
    cpu: 2
    memory: 4G
  production:
    cpu: 4
    memory: 8G

# Component definitions
components:
  web:
    image: myorg/web:${app_version}
    replicas: ${replicas}
    ports:
      - 3000:3000
    environment:
      NODE_ENV: ${env_type}
      API_URL: http://api:8080
      ENABLE_ANALYTICS: ${enable_monitoring}
    resources:
      cpu: ${presets[env_type].cpu}
      memory: ${presets[env_type].memory}
    health_check:
      type: http
      path: /health
      port: 3000
      interval: 30s
    depends_on:
      - api

  api:
    image: myorg/api:${app_version}
    replicas: ${replicas}
    ports:
      - 8080:8080
    environment:
      NODE_ENV: ${env_type}
      DATABASE_URL: postgres://app:${database_password}@database:5432/app
      REDIS_URL: redis://cache:6379
      LOG_LEVEL: ${env_type == 'development' ? 'debug' : 'info'}
    resources:
      cpu: ${presets[env_type].cpu}
      memory: ${presets[env_type].memory}
    health_check:
      type: http
      path: /api/health
      port: 8080
    depends_on:
      - database
      - cache
    secrets:
      - database_password
      - jwt_secret

  database:
    image: postgres:15
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${database_password}
      POSTGRES_DB: app
    volumes:
      - db-data:/var/lib/postgresql/data
    resources:
      cpu: 1
      memory: 2G
      storage: ${database_size}
    health_check:
      type: tcp
      port: 5432

  cache:
    image: redis:7-alpine
    ports:
      - 6379:6379
    command: ["redis-server", "--maxmemory", "256mb", "--maxmemory-policy", "allkeys-lru"]
    resources:
      cpu: 0.5
      memory: 512M
    health_check:
      type: tcp
      port: 6379

  # Conditional component - only included when monitoring is enabled
  prometheus:
    condition: ${enable_monitoring}
    image: prom/prometheus:latest
    ports:
      - 9090:9090
    volumes:
      - prometheus-config:/etc/prometheus
    config:
      prometheus.yml: |
        global:
          scrape_interval: 15s
        scrape_configs:
          - job_name: 'api'
            static_configs:
              - targets: ['api:8080']

# Secrets definition
secrets:
  database_password:
    generate: true
    length: 32
  jwt_secret:
    generate: true
    length: 64

# Persistent volumes
volumes:
  db-data:
    size: ${database_size}
  prometheus-config:
    size: 1Gi

# Network exposure
expose:
  - component: web
    port: 3000
    public: true
    
  - component: api
    port: 8080
    public: true
    path: /api
    
  - component: prometheus
    condition: ${enable_monitoring}
    port: 9090
    public: true
    path: /metrics

# Lifecycle hooks
hooks:
  post_create:
    - name: Run database migrations
      component: api
      command: ["npm", "run", "db:migrate"]
      
    - name: Seed development data
      condition: ${env_type == 'development'}
      component: api
      command: ["npm", "run", "db:seed"]

  pre_delete:
    - name: Create backup
      condition: ${env_type == 'production'}
      command: |
        teabar checkpoint create ${ENV_NAME} --name "pre-delete-backup"

Step 3: Blueprint Composition

Base Blueprints

Create base blueprints that others can extend:

# blueprints/base/nodejs.yaml
name: nodejs-base
version: "1.0"
abstract: true  # Cannot be used directly

parameters:
  node_version:
    type: string
    default: "20"
  
components:
  app:
    image: node:${node_version}-alpine
    environment:
      NODE_ENV: ${env_type}
    health_check:
      type: http
      path: /health
      port: 3000

Extending Blueprints

# blueprints/api-service.yaml
name: api-service
version: "1.0"
extends: nodejs-base

parameters:
  # Inherits node_version from base
  enable_swagger:
    type: boolean
    default: true

components:
  app:
    # Merges with base app component
    image: myorg/api:${app_version}
    environment:
      SWAGGER_ENABLED: ${enable_swagger}

Blueprint Modules

Create reusable modules:

# blueprints/modules/postgres.yaml
name: postgres-module
version: "1.0"
type: module

parameters:
  postgres_version:
    type: string
    default: "15"
  storage_size:
    type: string
    default: "10Gi"

components:
  database:
    image: postgres:${postgres_version}
    environment:
      POSTGRES_USER: ${db_user}
      POSTGRES_PASSWORD: ${db_password}
      POSTGRES_DB: ${db_name}
    volumes:
      - db-data:/var/lib/postgresql/data
    resources:
      storage: ${storage_size}

volumes:
  db-data:
    size: ${storage_size}

exports:
  connection_string: postgres://${db_user}:${db_password}@database:5432/${db_name}

Use modules in blueprints:

# blueprints/my-app.yaml
name: my-app
version: "1.0"

imports:
  - module: postgres-module
    as: db
    params:
      postgres_version: "15"
      storage_size: "20Gi"
      db_user: myapp
      db_password: ${secrets.db_password}
      db_name: myapp

components:
  api:
    image: myorg/api:latest
    environment:
      DATABASE_URL: ${db.connection_string}

Step 4: Validation and Testing

Schema Validation

# Validate blueprint syntax
teabar blueprint validate blueprints/full-stack-app.yaml

# Validate with specific parameters
teabar blueprint validate blueprints/full-stack-app.yaml 
  --var env_type=production 
  --var replicas=3

Dry Run

# See what would be created without actually creating it
teabar env create test-env 
  --blueprint full-stack-app 
  --var env_type=staging 
  --dry-run

Blueprint Testing

# blueprints/full-stack-app.test.yaml
name: full-stack-app-tests
blueprint: full-stack-app

tests:
  - name: Default parameters work
    params: {}
    expect:
      components:
        - web
        - api
        - database
        - cache
      
  - name: Production has more resources
    params:
      env_type: production
    expect:
      components.api.resources.cpu: 4
      components.api.resources.memory: 8G
      
  - name: Monitoring adds prometheus
    params:
      enable_monitoring: true
    expect:
      components:
        - prometheus
      expose:
        - path: /metrics

Run tests:

teabar blueprint test blueprints/full-stack-app.yaml

Step 5: Publishing Blueprints

Private Registry

# Publish to your organization's registry
teabar blueprint publish blueprints/full-stack-app.yaml 
  --registry myorg

# List published blueprints
teabar blueprint list --registry myorg

# Use published blueprint
teabar env create my-env --blueprint myorg/full-stack-app:2.0

Version Management

# Publish specific version
teabar blueprint publish blueprints/full-stack-app.yaml 
  --version 2.1.0

# Publish as latest
teabar blueprint publish blueprints/full-stack-app.yaml 
  --version 2.1.0 
  --latest

# List versions
teabar blueprint versions myorg/full-stack-app

Documentation

Add documentation to your blueprint:

# blueprints/full-stack-app.yaml
name: full-stack-app
version: "2.0"
description: Full-stack application with web frontend, API backend, database, and cache

documentation:
  overview: |
    This blueprint creates a complete full-stack application environment
    with the following components:
    
    - **Web**: React frontend served by Node.js
    - **API**: Express.js REST API
    - **Database**: PostgreSQL for data persistence
    - **Cache**: Redis for session storage and caching
    
  getting_started: |
    1. Create an environment:
       ```bash
       teabar env create my-app --blueprint full-stack-app
       ```
    
    2. Access the application:
       ```bash
       teabar env info my-app --endpoints
       ```
    
  parameters:
    env_type: |
      Controls resource allocation and feature flags.
      - `development`: Minimal resources, debug logging
      - `staging`: Production-like with debug features
      - `production`: Full resources, optimized settings
      
  examples:
    - name: Development environment
      command: teabar env create dev --blueprint full-stack-app
      
    - name: Production-like staging
      command: |
        teabar env create staging 
          --blueprint full-stack-app 
          --var env_type=staging 
          --var replicas=2 
          --var enable_monitoring=true

View documentation:

teabar blueprint docs full-stack-app

Best Practices

1. Use Descriptive Names

# Good
parameters:
  database_connection_pool_size:
    type: integer
    description: Maximum number of database connections

# Avoid
parameters:
  db_pool:
    type: integer

2. Provide Sensible Defaults

parameters:
  replicas:
    type: integer
    default: 1  # Safe default
    min: 1
    max: 10

3. Use Conditions Wisely

components:
  debug-tools:
    condition: ${env_type == 'development'}
    image: debug-tools:latest

4. Document Everything

parameters:
  feature_flags:
    type: array
    description: |
      List of feature flags to enable. Available flags:
      - `new_checkout`: New checkout flow
      - `dark_mode`: Dark mode support
      - `analytics`: Enhanced analytics

5. Test Your Blueprints

Always test with different parameter combinations before publishing.

Summary

You’ve learned how to:

  • Design blueprints with parameters and components
  • Use composition with base blueprints and modules
  • Validate and test blueprints
  • Publish and version blueprints
  • Document blueprints for your team

Next Steps

ende