Skip to content

RSGo Manifest Schema

The RSGo Manifest is the native stack definition format for ReadyStackGo. It provides type-validated variables, rich metadata, multi-stack support, and modular composition through includes.

version: "1.0" # Format version (optional)
metadata: # Product/Stack metadata
name: My Product
productVersion: "1.0.0" # Makes this a Product (deployable)
...
sharedVariables: # Variables shared across all stacks (Multi-Stack only)
REGISTRY: ...
variables: # Variables for this stack (Single-Stack or Fragment)
PORT: ...
stacks: # Stack definitions (Multi-Stack only)
api:
include: api.yaml
db:
services: ...
services: # Service definitions (Single-Stack or Fragment)
app: ...
volumes: # Volume definitions
data: {}
networks: # Network definitions
frontend: {}

A single-stack product contains services directly at the root level:

metadata:
name: Whoami
productVersion: "1.0.0" # ← Makes it a Product
variables:
PORT:
type: Port
default: "8080"
services:
whoami:
image: traefik/whoami:latest
ports:
- "${PORT}:80"

A multi-stack product contains multiple stacks with shared variables:

metadata:
name: Enterprise Platform
productVersion: "3.1.0" # ← Makes it a Product
sharedVariables: # ← Available to all stacks
REGISTRY:
type: String
default: myregistry.io
stacks:
api:
include: api.yaml # ← External fragment
monitoring:
services: # ← Inline stack
prometheus: ...

A fragment has no productVersion and can only be included from a product:

# identity.yaml - Fragment (no productVersion)
metadata:
name: Identity Access
description: Identity Provider
variables:
CERT_PATH:
type: String
default: /etc/ssl/certs/identity.pfx
services:
identity-api:
image: ${REGISTRY}/identity:latest # ← Uses shared variable

PropertyTypeRequiredDescription
namestringYesDisplay name of the product
productIdstringNoUnique product identifier for grouping versions across sources. Uses reverse domain notation (e.g., com.example.myproduct). If not set, defaults to sourceId:name.
descriptionstringNoDescription of what the product does
productVersionstringYes*Version string (e.g., “3.1.0”). *Required for Products
authorstringNoAuthor or maintainer name
documentationstringNoURL to documentation
iconstringNoURL to icon image for UI display
categorystringNoCategory for filtering (e.g., “Database”, “CMS”)
tagsstring[]NoTags for search and filtering

The productId field is used to group different versions of the same product together, even when they come from different sources (local directory, Git repository, registry).

Use cases:

  • Migrate a product from local development to a Git repository while maintaining version history
  • Allow upgrades between versions from different sources
  • Prevent accidental grouping of unrelated products with the same name

Recommendations:

  • Use reverse domain notation: com.yourcompany.productname
  • Keep it stable across versions - changing productId creates a new product group
  • If not specified, RSGO generates an ID as sourceId:name

Example:

metadata:
name: WordPress
productId: org.wordpress.stack # Unique identifier across all sources
description: Production-ready WordPress stack with MySQL backend
productVersion: "6.0.0"
author: ReadyStackGo Team
documentation: https://docs.example.com/wordpress
icon: https://example.com/icons/wordpress.png
category: CMS
tags:
- wordpress
- cms
- blog
- mysql
CategoryDescription
CMSContent Management Systems
DatabaseDatabases and data stores
MonitoringMonitoring, logging, and observability
IdentityAuthentication and authorization
MessagingMessage brokers and queues
CacheCaching systems
StorageFile storage and object storage
TestingTest and debug tools
EnterpriseEnterprise applications
ExamplesExample and demo stacks

Variables allow users to configure a product before deployment. They are displayed as form fields in the ReadyStackGo UI.

PropertyTypeRequiredDescription
labelstringNoHuman-readable label
descriptionstringNoHelp text shown in UI
typestringNoVariable type (default: String)
defaultstringNoDefault value
requiredbooleanNoWhether the variable must be provided
placeholderstringNoPlaceholder text for input field
patternstringNoRegex pattern for validation
patternErrorstringNoError message when pattern fails
optionsarrayNoOptions for Select type
minnumberNoMinimum value for Number type
maxnumberNoMaximum value for Number type
groupstringNoGroup name for UI organization
orderintegerNoDisplay order within group

For complete variable type reference, see Variable Types.

Variables can be organized into groups for better UX:

variables:
# Network Group
HTTP_PORT:
label: HTTP Port
type: Port
default: "80"
group: Network
order: 1
HTTPS_PORT:
label: HTTPS Port
type: Port
default: "443"
group: Network
order: 2
# Database Group
DB_HOST:
label: Database Host
type: String
default: localhost
group: Database
order: 1

Services define the Docker containers to deploy.

PropertyTypeRequiredDescription
imagestringYesDocker image (e.g., nginx:latest)
containerNamestringNoContainer name (default: stack_servicename)
portsstring[]NoPort mappings (host:container)
environmentobjectNoEnvironment variables
volumesstring[]NoVolume mappings
networksstring[]NoNetworks to connect
dependsOnstring[]NoService dependencies
restartstringNoRestart policy
commandstringNoCommand override
entrypointstringNoEntrypoint override
workingDirstringNoWorking directory
userstringNoUser to run as
labelsobjectNoContainer labels
healthCheckobjectNoHealth check configuration
services:
api:
image: ${REGISTRY}/api:${VERSION}
containerName: my-api
ports:
- "${API_PORT}:8080"
- "8443:8443"
environment:
ASPNETCORE_ENVIRONMENT: ${ENVIRONMENT}
ConnectionStrings__Database: ${DB_CONNECTION}
LOG_LEVEL: ${LOG_LEVEL}
volumes:
- api_data:/app/data
- ./config:/app/config:ro
networks:
- frontend
- backend
dependsOn:
- database
- cache
restart: unless-stopped
healthCheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
startPeriod: 40s
ports:
- "8080:80" # host:container
- "${PORT}:80" # variable substitution
- "127.0.0.1:8080:80" # bind to specific IP
- "8080-8090:80-90" # port range
PolicyDescription
noNever restart (default)
on-failureRestart on non-zero exit
unless-stoppedAlways restart unless explicitly stopped
alwaysAlways restart
healthCheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
startPeriod: 40s

Services can be loaded from multiple files to better organize large service definitions:

services:
include:
- Contexts/projectmanagement.yaml
- Contexts/memo.yaml
# Direct services can also be combined:
health-monitor:
image: monitor:latest

Service Include Features:

  • Services from all include files are merged into a single dictionary
  • Can be combined with direct service definitions
  • Perfect for large fragments with many services (bounded contexts)
  • Include paths are relative to the fragment manifest

Example Use Case - Bounded Contexts:

# business-services.yaml (fragment)
metadata:
name: Business Services
description: All business bounded context services
variables:
REDIS_CONNECTION:
label: Redis Connection
type: String
default: cachedata:6379
services:
include:
- Contexts/projectmanagement.yaml
- Contexts/memo.yaml
- Contexts/discussions.yaml

Each included file is a standard fragment with its own services:

Contexts/projectmanagement.yaml
metadata:
name: ProjectManagement
description: Project Management bounded context
services:
project-api:
image: amssolution/project-api:latest
environment:
REDIS_CONNECTION: ${REDIS_CONNECTION}
project-web:
image: amssolution/project-web:latest

volumes:
# Named volume (managed by Docker)
app_data: {}
# Volume with driver options
db_data:
driver: local
driverOpts:
type: none
o: bind
device: /mnt/data
# External volume (already exists)
shared_data:
external: true

networks:
# Default bridge network
frontend:
driver: bridge
# External network (already exists)
proxy:
external: true

Variables defined in sharedVariables are available to all stacks:

sharedVariables:
REGISTRY:
label: Docker Registry
type: String
default: docker.io
LOG_LEVEL:
label: Log Level
type: Select
options:
- value: debug
- value: info
- value: error
default: info
stacks:
api:
services:
api:
image: ${REGISTRY}/api:latest # Uses REGISTRY
environment:
LOG_LEVEL: ${LOG_LEVEL} # Uses LOG_LEVEL

Each stack can be:

  • Include: Reference to an external fragment file
  • Inline: Full stack definition within the product
stacks:
# Include external file
identity:
include: identity/identity-access.yaml
# Include with variable override
api:
include: api/api.yaml
variables:
LOG_LEVEL:
default: debug # Override default for this stack
# Inline definition
monitoring:
metadata:
name: Monitoring
services:
prometheus:
image: prom/prometheus:latest

Stacks can override shared variable defaults:

sharedVariables:
LOG_LEVEL:
type: Select
options:
- value: debug
- value: info
- value: error
default: info # Default for most stacks
stacks:
identity:
include: identity.yaml
variables:
LOG_LEVEL:
default: debug # Identity needs more logging

Value Resolution:

PrioritySource
1 (highest)User input
2Stack variable override
3Shared variable default
4 (lowest)Empty

Include paths are relative to the product manifest:

stacks/
└── myproduct/
├── myproduct.yaml # include: identity/stack.yaml
└── identity/
└── stack.yaml # ← Resolved here

Variables are substituted using ${VARIABLE_NAME} syntax:

variables:
REGISTRY:
default: docker.io
VERSION:
default: "1.0.0"
PORT:
type: Port
default: "8080"
services:
app:
image: ${REGISTRY}/myapp:${VERSION} # docker.io/myapp:1.0.0
ports:
- "${PORT}:80" # 8080:80
environment:
API_URL: http://${HOST}:${PORT} # http://host:8080

stacks/
├── whoami.yaml # Simple single-stack product
└── wordpress.yaml # WordPress product
stacks/
└── enterprise-platform/
├── enterprise-platform.yaml # Product manifest
├── IdentityAccess/
│ └── identity-access.yaml # Fragment
└── Infrastructure/
└── monitoring.yaml # Fragment

metadata:
name: Whoami
description: Simple HTTP service for testing
productVersion: "1.0.0"
category: Testing
tags:
- whoami
- testing
variables:
PORT:
label: Port
description: Port to access the service
type: Port
default: "8081"
group: Network
services:
whoami:
image: traefik/whoami:latest
ports:
- "${PORT}:80"
restart: unless-stopped
metadata:
name: PostgreSQL
description: PostgreSQL database server
productVersion: "15.0.0"
category: Database
variables:
POSTGRES_PORT:
label: Port
type: Port
default: "5432"
group: Network
POSTGRES_USER:
label: Username
type: String
default: postgres
group: Authentication
POSTGRES_PASSWORD:
label: Password
type: Password
required: true
group: Authentication
POSTGRES_DB:
label: Database Name
type: String
default: postgres
group: Database
services:
postgres:
image: postgres:15
ports:
- "${POSTGRES_PORT}:5432"
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
healthCheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres_data: {}
metadata:
name: Enterprise Platform
description: Complete enterprise platform with modular components
productVersion: "3.1.0"
category: Enterprise
sharedVariables:
REGISTRY:
label: Docker Registry
type: String
default: myregistry.io
group: Registry
ENVIRONMENT:
label: Environment
type: Select
options:
- value: development
label: Development
- value: staging
label: Staging
- value: production
label: Production
default: development
group: General
LOG_LEVEL:
label: Log Level
type: Select
options:
- value: Debug
- value: Information
- value: Warning
- value: Error
default: Warning
group: Logging
DB_CONNECTION:
label: Database Connection
type: SqlServerConnectionString
group: Database
stacks:
identity:
include: IdentityAccess/identity-access.yaml
variables:
LOG_LEVEL:
default: Debug # Identity needs verbose logging
api:
include: API/api.yaml
monitoring:
metadata:
name: Monitoring
variables:
GRAFANA_PORT:
label: Grafana Port
type: Port
default: "3000"
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
restart: unless-stopped
grafana:
image: grafana/grafana:latest
ports:
- "${GRAFANA_PORT}:3000"
dependsOn:
- prometheus
restart: unless-stopped

  1. Scan: Recursively scan stacks/ for *.yaml and *.yml files
  2. Parse: Parse each manifest file
  3. Classify:
    • Has metadata.productVersionProduct (load)
    • No productVersionFragment (skip, load via include)
  4. Resolve Includes: Resolve include paths relative to product manifest
  5. Merge Variables: Merge sharedVariables with stack variables