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:
| Type | Default Port | Use Case | Special Features |
|---|---|---|---|
react | 3000 | React/Vue SPA with client-side routing | Static build serving, SPA fallback |
nodejs | 3000 | Node.js APIs, Express, NestJS | Standard Node.js runtime |
flask | 5000 | Python Flask/FastAPI applications | Python WSGI/ASGI support |
rshiny | 3838 | R Shiny interactive dashboards | R Shiny server runtime |
static | 80 | Static HTML/CSS/JS sites | Nginx static file serving |
fullstack | 3000, 8000 | Monorepo with frontend + backend | Multiple port exposure |
mcp_server | 8080 | MCP protocol tool servers | MCP-specific configurations |
custom | 8080 | Any other application type | No 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 numbername: Friendly name for the port (default: "http")expose: Whether to expose externally (default: true)target_port: Target port if different fromport(optional)
App containers run as a non-root user and always listen on the platform's fixed internal port. The port you declare in the manifest becomes the Kubernetes Service (external) port, which is mapped down to the internal port via targetPort. The platform sets the PORT environment variable to the internal port, so your application should bind to PORT rather than hard-coding a port number.
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 descriptioninject_as: How to inject the variable -env(default),file, orconfig
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 filesindex: Index file name (default: index.html)spa: Enable SPA routing fallback (default: true for react)config_file: Runtime config injection file pathconfig_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
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 tohealth_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:
| Field | Default |
|---|---|
cpu_request | 100m |
memory_request | 256Mi |
cpu_limit | 500m |
memory_limit | 512Mi |
ephemeral_storage | not set |
gpu | not set |
Recommended Resources by App Type:
| App Type | CPU Request | Memory Request | CPU Limit | Memory Limit |
|---|---|---|---|---|
| React/Static | 50m | 128Mi | 200m | 256Mi |
| Node.js API | 100m | 256Mi | 500m | 512Mi |
| Flask API | 200m | 512Mi | 1000m | 1Gi |
| Heavy Processing | 500m | 1Gi | 2000m | 2Gi |
1000m= 1 CPU core500m= 0.5 CPU cores100m= 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 field:
typeis the only required field (versiondefaults to "1.0") - Invalid type: Must be one of the 8 supported types (react, nodejs, static, fullstack, flask, rshiny, mcp_server, custom)
- Wrong field types: Fields must match their expected types (e.g.,
portmust be an integer,envmust be a list) - Invalid resource format: Resource strings must use Kubernetes format (e.g., "500m", "1Gi"); invalid formats are rejected when the deployment is created