Skip to main content

The strongly.manifest.yaml File

The manifest file provides declarative configuration for building and deploying your application. It must be placed in your project root alongside the Dockerfile.

Basic Structure

# strongly.manifest.yaml (place in project root)
version: "1.0"
type: nodejs # react, nodejs, flask, rshiny, mcp_server, static, fullstack, custom
name: my-app
description: Brief description of your application
author: Your Name or Organization
homepage: https://github.com/yourorg/my-app
license: MIT
icon: "https://example.com/icon.png"
tags:
- api
- backend

ports:
- port: 3000
name: http
expose: true
target_port: 3000 # Optional: if different from port

env:
- name: NODE_ENV
value: "production"
required: true

- name: DATABASE_URL
value: "" # User must provide
required: true
secret: true # Stored as Kubernetes Secret
description: PostgreSQL connection string
inject_as: env # How to inject: 'env' (default), 'file', 'config'

runtime:
command: ["node", "server.js"]
working_dir: /app
health_check_path: /health
readiness_check_path: /ready # Defaults to health_check_path if not set
startup_timeout: 60 # Startup timeout in seconds

health_check:
path: /health
initial_delay: 15
period: 30

resources:
cpu_request: "100m"
memory_request: "256Mi"
cpu_limit: "500m"
memory_limit: "512Mi"
ephemeral_storage: "1Gi" # Optional: ephemeral storage limit
gpu: 1 # Optional: number of GPUs required

Application Types

The type field determines default configuration and runtime behavior:

TypeDefault PortUse CaseSpecial Features
react3000React/Vue SPA with client-side routingNginx-based serving, SPA fallback
nodejs3000Node.js APIs, Express, NestJSStandard Node.js runtime
flask5000Python Flask/FastAPI applicationsPython WSGI/ASGI support
rshiny3838R Shiny interactive dashboardsR Shiny server runtime
static80Static HTML/CSS/JS sitesNginx static file serving
fullstack3000, 8000Monorepo with frontend + backendMultiple port exposure
mcp_server8080MCP protocol tool serversMCP-specific configurations
custom8080Any other application typeNo special defaults

Configuration Sections

Ports

Define which ports your application listens on:

ports:
- port: 3000
name: http
expose: true # Expose externally via ingress
target_port: 3000 # Optional: target port if different from port
- port: 8080
name: metrics
expose: false # Internal only

Fields:

  • port: Port number (1-65535)
  • name: Friendly name for the port (default: "http")
  • expose: Whether to expose externally (default: true)
  • target_port: Target port if different from port (optional)

Environment Variables

Define runtime configuration with proper metadata:

env:
# Regular environment variable
- name: API_URL
value: "https://api.example.com"
required: false
description: Backend API endpoint
inject_as: env # How to inject: 'env' (default), 'file', 'config'

# Secret (passwords, API keys, tokens)
- name: API_KEY
value: "" # Must be provided by user
required: true
secret: true # Encrypted in Kubernetes
description: Third-party API key

# Build-time variable
- name: REACT_APP_VERSION
value: "1.0.0"
buildtime: true # Passed as Docker build arg
description: App version

Fields:

  • name: Variable name (uppercase with underscores)
  • value: Default value (can be empty for required vars)
  • required: Whether variable must have a value (default: false)
  • secret: Store as Kubernetes Secret (default: false)
  • buildtime: Pass to Docker build as ARG (default: false)
  • description: User-friendly description
  • inject_as: How to inject the variable - env (default), file, or config
Secrets Management

Variables marked as secret: true are stored in Kubernetes Secrets and encrypted at rest. Use this for passwords, API keys, and tokens.

React/Static App Configuration

For React and static applications, configure nginx serving:

type: react
static:
root: /app/build
index: index.html
spa: true # Fallback to index.html for client-side routing
config_file: /app/build/config.js
config_placeholder: __APP_CONFIG__

build:
args:
NODE_ENV: production
output_dir: /app/build

Static Fields:

  • root: Directory containing built static files
  • index: Index file name (default: index.html)
  • spa: Enable SPA routing fallback (default: true for react)
  • config_file: Runtime config injection file path
  • config_placeholder: Placeholder to replace with config

Health Checks

Your app must expose a health endpoint for Kubernetes liveness and readiness probes:

health_check:
path: /health
port: 3000
initial_delay: 10 # Seconds before first check
period: 30 # Check every 30 seconds
timeout: 3
failure_threshold: 3

Implementation Example (Express.js):

app.get('/health', (req, res) => {
res.status(200).json({ status: 'ok' });
});

Implementation Example (Flask):

@app.route('/health')
def health():
return {'status': 'ok'}, 200
Required Endpoint

Health checks are mandatory. If your app doesn't respond to health checks, Kubernetes will continuously restart it.

Runtime Configuration

Customize the container runtime:

runtime:
command: ["node", "dist/server.js"]
working_dir: /app
health_check_path: /health
readiness_check_path: /ready # Defaults to health_check_path
startup_timeout: 60 # Startup timeout in seconds (default: 60)
user: appuser # User to run as (if not set in Dockerfile)

Fields:

  • command: Override container CMD (string or array format)
  • working_dir: Working directory (default: /app)
  • health_check_path: Health check endpoint path (default: /health)
  • readiness_check_path: Readiness check path (defaults to health_check_path)
  • startup_timeout: Startup timeout in seconds (default: 60)
  • user: User to run as (optional)

Resource Requirements

Set CPU and memory limits to ensure stable performance:

resources:
cpu_request: "100m" # 0.1 CPU cores (default)
memory_request: "256Mi" # 256 MiB (default)
cpu_limit: "500m" # 0.5 CPU cores (default)
memory_limit: "512Mi" # 512 MiB (default)
ephemeral_storage: "1Gi" # Optional: ephemeral storage limit
gpu: 1 # Optional: number of GPUs required

Default Resource Values:

FieldDefault
cpu_request100m
memory_request256Mi
cpu_limit500m
memory_limit512Mi
ephemeral_storagenot set
gpunot set

Recommended Resources by App Type:

App TypeCPU RequestMemory RequestCPU LimitMemory Limit
React/Static50m128Mi200m256Mi
Node.js API100m256Mi500m512Mi
Flask API200m512Mi1000m1Gi
Heavy Processing500m1Gi2000m2Gi
CPU Units
  • 1000m = 1 CPU core
  • 500m = 0.5 CPU cores
  • 100m = 0.1 CPU cores

Proxy Configuration

Configure ingress proxy behavior:

proxy:
websocket: true # Enable WebSocket support
timeout: 30 # Request timeout in seconds (default: 30)
preserve_host: false # Preserve original host header
rewrite_paths: # Path rewriting rules
"/api": "/api/v1"
headers: # Additional headers to add
X-App-Version: "1.0.0"

Fields:

  • websocket: Enable WebSocket proxying (default: false)
  • timeout: Proxy timeout in seconds (default: 30)
  • preserve_host: Preserve original host header (default: false)
  • rewrite_paths: Path rewriting rules (optional)
  • headers: Additional headers to add (optional)

MCP Configuration

For MCP server applications (type: mcp_server):

mcp:
protocol_version: "1.0"
transport: http # 'http', 'stdio', 'sse'
capabilities:
- tools
- prompts
- resources
authentication_required: true
tools:
- name: example_tool
description: An example tool
parameters:
type: object
properties:
input:
type: string
required: [input]
prompts:
- name: analyze_data
description: Analyzes data
arguments:
- name: data_source
required: true
resources:
- uri: "mcp://data/*"
name: "Data Resource"
description: "Access to data resources"

Complete Examples

Node.js API

version: "1.0"
type: nodejs
name: user-api
description: REST API for user management
author: Acme Corp
tags: [nodejs, api, backend]

ports:
- port: 3000
name: http
expose: true

env:
- name: NODE_ENV
value: "production"
required: true

- name: DATABASE_URL
value: ""
required: true
secret: true
description: PostgreSQL connection string

- name: JWT_SECRET
value: ""
required: true
secret: true
description: Secret for JWT signing

runtime:
command: ["node", "dist/server.js"]
working_dir: /app
health_check_path: /health

health_check:
path: /health
initial_delay: 15
period: 30

proxy:
websocket: true
timeout: 30

resources:
cpu_request: "100m"
memory_request: "256Mi"
cpu_limit: "500m"
memory_limit: "512Mi"

React SPA

version: "1.0"
type: react
name: admin-dashboard
description: Admin dashboard SPA
author: Acme Corp
tags: [react, frontend]

ports:
- port: 3000
name: http
expose: true

static:
root: /app/build
index: index.html
spa: true
config_file: /app/build/config.js
config_placeholder: __APP_CONFIG__

build:
args:
NODE_ENV: production
REACT_APP_VERSION: "1.0.0"
output_dir: /app/build

env:
- name: REACT_APP_API_URL
value: "https://api.acme.com"
buildtime: true
description: Backend API endpoint

health_check:
path: /
initial_delay: 5
period: 30

resources:
cpu_request: "50m"
memory_request: "128Mi"
cpu_limit: "200m"
memory_limit: "256Mi"

Flask API

version: "1.0"
type: flask
name: ml-api
description: Machine learning inference API
author: Data Team
tags: [python, flask, ml]

ports:
- port: 5000
name: http
expose: true

env:
- name: FLASK_ENV
value: "production"
required: true

- name: MODEL_PATH
value: "/app/models/model.pkl"
description: Path to ML model file

- name: REDIS_URL
value: ""
required: true
secret: true
description: Redis cache connection string

runtime:
command: ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]
working_dir: /app
health_check_path: /health

health_check:
path: /health
port: 5000
initial_delay: 20
period: 30
timeout: 5

resources:
cpu_request: "200m"
memory_request: "512Mi"
cpu_limit: "1000m"
memory_limit: "1Gi"

R Shiny Dashboard

version: "1.0"
type: rshiny
name: analytics-dashboard
description: Interactive R Shiny analytics dashboard
author: Data Team
tags: [rshiny, analytics, dashboard]

ports:
- port: 3838
name: http
expose: true

env:
- name: SHINY_LOG_LEVEL
value: "INFO"
description: Shiny log level

runtime:
working_dir: /app
health_check_path: /health

health_check:
path: /
initial_delay: 15
period: 30

resources:
cpu_request: "200m"
memory_request: "512Mi"
cpu_limit: "1000m"
memory_limit: "1Gi"

MCP Server

version: "1.0"
type: mcp_server
name: my-mcp-server
description: MCP server providing custom tools
author: Your Organization
homepage: https://github.com/yourorg/mcp-server
license: MIT
tags: [mcp, tools]

ports:
- port: 8080
name: http
expose: true

env:
- name: LOG_LEVEL
value: "info"
description: Logging level

runtime:
command: ["python", "server.py"]
working_dir: /app
health_check_path: /health
startup_timeout: 60

health_check:
path: /health
initial_delay: 10
period: 30

resources:
cpu_request: "100m"
memory_request: "256Mi"
cpu_limit: "500m"
memory_limit: "512Mi"

mcp:
protocol_version: "1.0"
transport: http
capabilities: [tools, prompts, resources]
authentication_required: true
tools:
- name: example_tool
description: An example tool that processes data
parameters:
type: object
properties:
input:
type: string
description: Input data to process
required: [input]

Validation

The platform validates your manifest during deployment. Common errors:

  • Missing required fields: version, type
  • Invalid type: Must be one of the supported types
  • Invalid port: Must be 1-65535
  • Invalid resource format: Must use Kubernetes format (e.g., "500m", "1Gi")
  • Secret without value: Required secrets need values (or user must provide)

Next Steps