Skip to content

MonkScript Reference

MonkScript is the YAML-based configuration language used by Monk to define templates.

Basic Syntax and Structure

MonkScript follows standard YAML syntax with some Monk-specific extensions. Each file defines a namespace and one or more entities that represent infrastructure components like applications, databases, or complete stacks.

File Layout

Every MonkScript file must begin with a namespace declaration, followed by entity definitions:

namespace: my-namespace
# Entity definitions follow
entity-one:
defines: runnable
# entity configuration...
entity-two:
defines: group
# entity configuration...

MonkScript files are usually named after the namespace they belong to and can be placed in any directory - no special project layout is required.

Naming Convention

All identifiers in MonkScript must use kebab-case (lowercase letters, numbers, and hyphens as separators):

# Correct (kebab-case)
my-entity:
defines: runnable
# Incorrect
MyEntity: # Don't use PascalCase
my_entity: # Don't use snake_case
myEntity: # Don't use camelCase

This naming convention applies to entity names, variable names, container names, service names, and other identifiers.

Namespace Paths

Namespace paths are used to reference entities within a namespace. They are always relative to the current namespace and are always kebab-case.

Although . can be used to reference the current namespace, it is recommended to use the namespace name directly.

Paths usually contain two segments separated by a /: <namespace>/<entity-name>. Nested paths are supported but discouraged as entities are usually flat.

namespace: my-namespace
my-entity:
defines: runnable

Path to the entity above is my-namespace/my-entity.

Paths can reference entities in other namespaces:

namespace: my-namespace
my-entity:
defines: runnable
inherits: other-namespace/my-entity

Entity Types

MonkScript supports four main entity types:

Runnable

A runnable is the basic unit of execution in Monk, defining one or more containers that run together in a single pod.

my-app:
defines: runnable
containers:
app:
image: nginx:latest
# Other sections

Group

A group collects multiple runnables and other entities that will be run together as a logical unit.

my-stack:
defines: group
members:
- my-namespace/my-app
- my-namespace/my-db
# Limited to variables and metadata

Entity Type Definition

An entity type definition creates a reusable template that can be instantiated. This is a powerful feature for creating your own abstractions.

my-entity:
defines: entity
schema:
# ...
# Define reusable components

Entity Instance

Creates an instance of a defined entity type.

my-instance:
defines: my-namespace/my-template
# Fields as defined in my-namespace/my-template

Deprecated: Fragments

Note: Fragments (configuration blocks without a defines property) are deprecated and should be avoided in new code.

Inheritance and Composition

The defines Property

The defines property specifies what type an entity is:

  • defines: runnable - Creates a runnable
  • defines: group - Creates a group
  • defines: entity - Creates an entity type definition
  • defines: my-namespace/my-entity - Creates an instance of an entity type

The inherits Property

The inherits property allows entities to inherit configuration from other entities:

my-app:
defines: runnable
inherits: my-namespace/common-config
# More specific configuration

When using inherits, configuration from the inherited entity is merged with the current entity:

  1. Simple values in the current entity override values from the inherited entity
  2. Lists are combined (with duplicates removed)
  3. Maps/objects are deeply merged, with current values taking precedence for duplicate keys
  4. This applies recursively to all nested configuration

Multiple inheritance is not supported - an entity can only inherit from one other entity.

Entity Sections by Type

Different entity types support different sections:

Runnable Sections

Runnables support the most comprehensive set of sections:

  • containers (required) - Container definitions
  • variables - Entity variables
  • files - File definitions
  • connections - Connections to other entities
  • services - Service definitions
  • check - Health/readiness checks
  • depends - Dependencies
  • recovery - Recovery configuration
  • affinity - Scheduling configuration
  • volumes - Persistent volume configuration
  • scale - Scaling configuration
  • metadata - Entity metadata

Group Sections

Groups are limited to:

  • variables - Entity variables
  • metadata - Entity metadata

Entity Type Definition Sections

Read the Entity Type Definitions section for more information.

Entity Instance Sections

Read the Entity Type Definitions section for more information.

Variables

Variables provide a way to parameterize your configuration and can be referenced throughout the entity:

variables:
port: 8080
database-url: "postgres://user:pass@host:5432/db"
debug-mode:
type: boolean
value: true
description: "Enable debug logging"
env: DEBUG_MODE # Exposed as an environment variable

Variables can be simple values or complex objects with type information and descriptions.

Containers

Containers define the actual execution units within a runnable (only valid in runnable entities):

containers:
web:
image: nginx:latest
image-tag: 1.21 # Can also use ArrowScript: <- $version
ports:
- "80:80" # Host:Container format
paths:
- "/data:/app/data" # Host:Container format
environment:
- "DEBUG=true"
bash: "nginx -g 'daemon off;'" # Command to run

Multiple containers can be defined within a single runnable, creating a pod-like deployment.

Services

Services define the endpoints that a runnable exposes (only valid in runnable entities):

services:
http:
container: web # Reference to the container
port: 80 # Container port
protocol: tcp # tcp or udp
publish: true # Expose to external network
host-port: 8080 # Port on the host
description: "HTTP endpoint"

Connections

Connections define how a runnable connects to services provided by other entities (only valid in runnable entities):

connections:
db:
target: my-namespace/database # Path to the target entity
service: postgres # Service name to connect to
description: "Main database connection"

Files

Files define configuration files to be created in containers (only valid in runnable entities):

files:
nginx-conf:
container: web
path: /etc/nginx/nginx.conf
mode: 0644 # File permissions (octal)
contents: |
server {
listen 80;
# ...
}

Checks

Checks allow you to define health and readiness checks for your runnables (only valid in runnable entities):

check:
readiness:
code: 'http-get("http://localhost:8080/health") nil? not'
period: 10 # Check interval in seconds
initialDelay: 5 # Wait before first check
attempts: 5 # Number of attempts before failing

The code field contains ArrowScript that should return a boolean value.

Dependencies

Dependencies define the order in which entities should be started (only valid in runnable entities):

depends:
wait-for:
- my-namespace/database
- my-namespace/redis

Or with timeout:

depends:
wait-for:
runnables:
- my-namespace/database
- my-namespace/redis
timeout: 300 # Seconds

Scaling

Configure horizontal scaling for your runnables (only valid in runnable entities):

scale:
value: 3 # Static number of instances
# Or dynamic scaling
value: "cpu() 0.8 gt? then(5) else(3)" # ArrowScript without <- prefix
min: 1 # Minimum instances
max: 10 # Maximum instances
interval: 30 # Check interval in seconds
throttle-up: 120 # Seconds between scale ups
throttle-down: 300 # Seconds between scale downs
# Metric-based scaling
metrics:
cpu: 0.7 # Target CPU utilization (70%)
memory: 0.8 # Target memory utilization (80%)

Volumes

Define persistent storage volumes (only valid in runnable entities):

volumes:
data:
kind: persistent # Volume type
size: 10 # Size in GB
path: /data # Mount path
# Backup configuration
backup:
every: 1
kind: day # hour, day, week
rotation-days: 7
start-time: "02:00" # 24-hour format

Affinity

Control where your runnable gets scheduled (only valid in runnable entities):

affinity:
tag: "production" # Run on nodes with this tag
name: "worker-1" # Or run on a specific node
ignore-pressure: false # Consider node resource pressure
resident: true # Reserve the node exclusively

Recovery

Configure how your runnable recovers from failures (only valid in runnable entities):

recovery:
after: 10 # Seconds before recovery
mode: default # Recovery mode: node, cluster, default
when: container-failure # Recovery trigger condition
kill-on-recovery: parent # What to kill during recovery

Metadata

Add descriptive information to your entities (valid in all entity types):

metadata:
name: "My Web Application"
description: "A simple web application with database"
website: "https://example.com"
source: "https://github.com/example/webapp"
publisher: "Example Corp"
icon: "https://example.com/icon.png"
tags: "web, database, production"
private: false # Whether to hide from catalog

ArrowScript

ArrowScript is an embedded scripting language that allows dynamic calculations and transformations within MonkScript. ArrowScript expressions begin with <- and can be used in most string or numeric fields within Monk YAML files. ArrowScripts are executed on Monk’s control plane at runtime instead of being simple macros.

ArrowScript has a concise concatenative syntax ideal for writing one-liners. You can think of it as Monk’s shell scripting language.

variables:
greeting: <- `Hello ${name}!` # Template strings
random-port: <- random(3000, 5000) # Operator calls
db-ready: <- $db "ready" eq # Value comparison

ArrowScript can be used for:

  • String interpolation a’la JavaScript template literals
  • Mathematical calculations
  • Conditional logic
  • Accessing other variables with $variable-name
  • Built-in operators and functions like random(), http-get(), etc.

In some contexts like scale.value and check.readiness.code, ArrowScript is written without the <- prefix.

Entity Type Definitions and Instances

Entity type definitions allow you to create custom resources that extend Monk with your own data structures and logic. Entities can store structured data and execute custom JavaScript code during their lifecycle.

Entity Type Definition

An entity type is defined with defines: entity and can include a schema to validate its structure:

namespace: example
database-type:
defines: entity
schema:
name:
type: string
version:
type: string
port:
type: integer
variables:
default-port: 5432

The schema property describes the entity structure and follows JSON Schema specification, similar to OpenAPI.

Entity Instances

Once an entity type is defined, you can create instances of it:

postgres-db:
defines: example/database-type
name: "main-database"
version: "14"
port: 5432

When you create an instance:

  1. The instance inherits all properties from the entity type definition
  2. The instance must provide values that match the schema
  3. You can override variables and metadata in the instance

Lifecycle Scripts

Entity types can include JavaScript (ES6) lifecycle scripts that execute during different phases:

database-type:
defines: entity
lifecycle:
create: |
function main(definition, state, context) {
console.log("Creating database:", definition.name);
// Create database logic here
return { "created": Date.now() };
}
start: |
function main(definition, state, context) {
console.log("Starting database:", definition.name);
// Start database logic here
return { ...state, "started": Date.now() };
}
stop: |
function main(definition, state, context) {
console.log("Stopping database:", definition.name);
// Stop database logic here
}
purge: |
function main(definition, state, context) {
console.log("Purging database:", definition.name);
// Delete database logic here
}

The main function receives up to 3 arguments:

  • definition - Entity data as defined in template
  • state - Saved data from previous executions (can be empty)
  • context - Additional data with properties like action, status, path

The returned object is saved as state and passed to subsequent operations.

Available Lifecycle Events

  • create - Triggered with first monk run
  • start - Triggered with every monk run or monk update
  • update - Triggered with monk update
  • stop - Triggered with monk stop
  • purge - Triggered with monk purge
  • sync - Triggered for any command that has no explicit script

Custom Actions

You can define custom actions that can be called with monk do:

database-type:
defines: entity
lifecycle:
backup: |
function main(definition, state, context) {
console.log("Backing up database:", definition.name);
// Backup logic here
return { ...state, "lastBackup": Date.now() };
}

To use a custom action:

monk do example/postgres-db/backup

Readiness Checks

Entity types can include readiness checks to determine when they’re ready:

database-type:
defines: entity
checks:
readiness:
code: |
function main(definition, state, context) {
// Test if database is ready
if (!isReady()) {
throw new Error("Database not ready yet");
}
return state;
}
period: 10 # Check interval in seconds
initialDelay: 5 # Wait before first check
attempts: 12 # Max attempts (fails after this)

Requiring Modules

Entity scripts can use built-in modules for additional functionality:

database-type:
defines: entity
requires:
- http
- secret
lifecycle:
create: |
const http = require("http");
const secret = require("secret");
function main(def, state, ctx) {
// Use Secret module
let password = secret.get(def.secret);
let bucketName = def.name;
let bucket = http.get(`https://api.example.com/buckets/${bucketName}`, {
headers: {
"Authorization": `Bearer ${password}`
}
});
return { bucketName: bucket.name };
}

Available modules include:

  • cli - CLI operations
  • secret - Secret management
  • fs - File system operations
  • parser - Parsing utilities
  • http - HTTP client
  • gcp, aws, azure, do - Cloud provider APIs

Entity References

Entities can reference other entities using ArrowScript:

my-app:
defines: runnable
variables:
db-host: <- entity-state("example/postgres-db") get-member("address")
db-port: <- entity("example/postgres-db") get-member("port")
containers:
app:
environment:
- <- `DB_HOST=${db-host}`
- <- `DB_PORT=${db-port}`

This allows components to properly reference and use resources managed by custom entities.

Complete Entity Type Example

namespace: example
cloud-bucket:
defines: entity
schema:
required: ["name", "region"]
name:
type: string
region:
type: string
public:
type: boolean
default: false
requires:
- cloud/aws
lifecycle:
create: |
function main(def, state, ctx) {
console.log("Creating bucket:", def.name);
let result = aws.createS3Bucket(def.name, {
region: def.region,
public: def.public
});
if (result.error) {
throw new Error("Failed to create bucket: " + result.error);
}
return {
"arn": result.arn,
"url": `https://${def.name}.s3.amazonaws.com`
};
}
purge: |
function main(def, state, ctx) {
console.log("Deleting bucket:", def.name);
let result = aws.deleteS3Bucket(def.name);
if (result.error) {
throw new Error("Failed to delete bucket: " + result.error);
}
}
check-access: |
function main(def, state, ctx) {
let result = aws.checkS3BucketAccess(def.name);
return { "accessible": result.accessible };
}
checks:
readiness:
code: |
function main(def, state, ctx) {
let result = aws.getS3Bucket(def.name);
if (result.error) {
throw new Error("Bucket not accessible yet");
}
return state;
}
period: 5
attempts: 10

Complete Example

Here’s a complete example that demonstrates many MonkScript features:

namespace: example
# A web application
web-app:
defines: runnable
metadata:
name: "Example Web App"
description: "A web application with database"
tags: "web, example"
variables:
http-port: 8080
version: "1.0.0"
debug: true
log-level: <- $debug ? "debug" : "info"
containers:
web:
image: nginx
image-tag: <- $version
ports:
- "80:80"
environment:
- <- `LOG_LEVEL=${log-level}`
services:
http:
container: web
port: 80
protocol: tcp
publish: true
host-port: <- $http-port
files:
nginx-conf:
container: web
path: /etc/nginx/conf.d/default.conf
contents: |
server {
listen 80;
location / {
root /usr/share/nginx/html;
}
}
check:
readiness:
code: "http-get(\"http://localhost:80\") nil? not"
period: 5
attempts: 3
scale:
value: 2
min: 1
max: 5

This example defines a web application that uses variables and ArrowScript, and defines containers, services, files, checks, and scaling options.