Marketplace routeros-app-yaml

RouterOS /app YAML format for container applications (7.21+ builtin app, 7.22+ custom YAML creation). Use when: writing or validating RouterOS /app YAML files, working with MikroTik container apps, building docker-compose-like definitions for RouterOS, creating /app store schemas, debugging /app validation errors, or when the user mentions /app, tikapp, or RouterOS container YAML.

install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/tikoci/routeros-app-yaml" ~/.claude/skills/aiskillstore-marketplace-routeros-app-yaml && rm -rf "$T"
manifest: skills/tikoci/routeros-app-yaml/SKILL.md
source content

RouterOS /app YAML Format (7.21+)

RouterOS 7.21 introduced the

/app
path (built-in app listing and management). The full YAML app creation feature (
/app/add
) appeared in 7.22 (first seen in 7.22beta5). Think of it as MikroTik's opinionated alternative to
docker-compose
— but it is NOT docker-compose, with significant differences.

What /app Is

The

/app
subsystem lets users define one or more containers as a single "application" in YAML. RouterOS parses the YAML, creates containers, volumes, networks, and config files, then manages the lifecycle.

Key concepts:

  • Each
    /app
    is defined by a YAML document with services, configs, volumes, and networks
  • The YAML is loaded into RouterOS via CLI (
    /app/add yaml-url=...
    ) or REST API
  • Built-in apps ship with RouterOS (visible at
    GET /rest/app
    )
  • Custom apps can be added from URLs or inline YAML
  • App stores (
    app-store-urls=
    ) provide curated collections

Critical Differences from docker-compose

Featuredocker-composeRouterOS /app
Port format
host:container[/protocol]
Two styles (see below)
Environment
KEY=value
or list
Same, but placeholders expand
VolumesNamed or bind mountsSubset — no bind mount options
NetworksFull docker network modelSimplified — name + external
BuildFull Dockerfile supportMinimal (context + dockerfile)
ConfigsDocker configs APIInline
content
only
Deploy/resourcesYesNo — not supported
Top-level
version:
Deprecated (was required)Not used
File extension
.yml
/
.yaml
.tikapp.yaml
(convention)

Top-Level Properties

PropertyTypeRequiredDescription
name
stringNoUnique identifier for the /app
descr
stringNoHuman-readable description shown in app UI
page
string (URI)NoProject homepage URL
category
string (enum)NoApp store classification
icon
string (URI)NoIcon URL (shown in WebFig with
show-in-webfig=yes
)
default-credentials
string or nullNo
username:password
shown in UI
url-path
stringNoURL path suffix for browser access (e.g.,
/admin
)
credentials
stringNoCredential hint (alternative to default-credentials)
option
booleanNoWhether app is optional
auto-update
booleanNoPull and restart containers on every boot
services
objectYesContainer service definitions (≥1 required)
volumes
objectNoNamed volume declarations
networks
objectNoNetwork declarations
configs
objectNoConfig file declarations with inline content

Category Values (Exhaustive)

productivity, storage, networking, development, communication,
file-management, search, video, media, media-management,
home-automation, monitoring, database, automation, ai,
messaging, radio, security, business

New categories appear when MikroTik adds built-in apps. The CI schema validation catches these.

Service Properties

Each key under

services:
defines one container. Required property:
image
.

PropertyTypeDescription
image
stringContainer image (omit registry to use
/container/config
's
registry-url
)
container_name
stringExplicit name; used as base for file paths under
/container
hostname
stringContainer hostname
entrypoint
string or string[]Override default entrypoint
command
string or string[]Override default command
ports
arrayPort mappings (see format section)
environment
object or array or nullEnvironment variables (
KEY=value
list or
{KEY: value}
map)
volumes
array of stringsVolume mounts (e.g.,
my-vol:/data
)
configs
array of objectsConfig file placements (
{source, target, mode}
)
restart
enum
no
,
always
,
on-failure
,
unless-stopped
depends_on
array or objectService dependency ordering
devices
array of stringsDevice mappings passed to container
user
stringUser to run container as
security_opt
array of stringsSecurity options
shm_size
stringShared memory size
stop_grace_period
string or intTime before SIGKILL
ulimits
objectResource limits (e.g.,
nofile: {soft: 65536, hard: 65536}
)
build
object or stringBuild configuration (context, dockerfile, args)
healthcheck
objectHealth check (test, interval, timeout, retries, start_period)
stdin_open
booleanKeep stdin open
expose
arrayInternal ports (not published to host)
secrets
array of stringsSecrets to expose
attach
booleanAttach to stdio

Port Format — Two Styles

RouterOS supports two port mapping string formats. Both are valid; new apps from 7.23beta2+ prefer the colon style.

Old OCI-style (pre-7.23)

[ip:]host_port:container_port[/tcp|/udp][:label]

Examples:

ports:
  - "8080:80/tcp"
  - "8443:443/tcp:https"
  - "192.168.1.1:53:53/udp:dns"

New RouterOS style (7.23+)

[ip:]host_port:container_port[:label][:tcp|:udp]

Protocol is appended with colon instead of slash:

ports:
  - "8080:80:web:tcp"
  - "8443:443:https:tcp"
  - "53:53:dns:udp"

Long-form (object) syntax

ports:
  - target: 80
    published: 8080
    protocol: tcp
    name: web
    app_protocol: http

IP Addresses and Placeholders in Ports

Port strings can include literal IPs or placeholder expressions:

ports:
  - "[accessIP]:[accessPort]:80/tcp:web"      # Old style with placeholders
  - "[accessIP]:[accessPort]:80:web:tcp"       # New style with placeholders

Placeholders

RouterOS expands these placeholders at deploy time:

PlaceholderExpands to
[accessIP]
IP address for accessing the app from outside
[accessPort]
Primary host port for external access
[accessPort2]
Secondary host port
[containerIP]
IP address assigned to the container
[routerIP]
Router's own IP address

Placeholders appear in port mappings, environment values, and config content.

Configs (Inline Files)

Top-level

configs:
declares config content; services reference them:

configs:
  my-config:
    content: |
      server {
        listen 80;
        server_name [accessIP];
      }

services:
  web:
    image: nginx:alpine
    configs:
      - source: my-config
        target: /etc/nginx/conf.d/default.conf
        mode: 0644

Volumes and Networks

volumes:
  app-data: {}      # Named volume (null or empty object)

networks:
  app-net:
    name: my-network
    external: true   # Use existing RouterOS network

Store Schema (app-store-urls)

RouterOS can load app collections from URLs configured via

app-store-urls=
. The store format is simply a YAML array of /app definitions:

- name: app-one
  services:
    web:
      image: nginx:alpine
- name: app-two
  services:
    db:
      image: postgres:16

Store files use the

.tikappstore.yaml
extension by convention.

REST API for /app

// List all /app entries (built-in + custom)
const apps = await fetch(`${base}/app`, auth).then(r => r.json());

// Each entry has: .id, name, yaml (raw YAML string), and metadata
// The 'yaml' field is a RouterOS string containing the full YAML document

// Add a custom /app from URL
await fetch(`${base}/app`, {
  method: "PUT",
  ...auth,
  body: JSON.stringify({ "yaml-url": "https://example.com/my-app.tikapp.yaml" }),
});

Note: The

/app
endpoint requires the container extra package to be installed.

JSON Schema for Validation

Two schema variants exist for each /app document:

SchemaPurposePort validationEnv var names
*.latest.json
CI/strict validationRegex patterns enforced
^[A-Z_][A-Z0-9_]*$
only
*.editor.json
Editor/SchemaStore UXNo regex (allows autocompletion)Case-insensitive

The strict schema has regex

pattern
on port strings which prevents VSCode autocompletion — the YAML extension won't suggest values for fields with patterns. The editor variant removes these patterns.

VSCode Integration

Add to VSCode settings for YAML autocompletion:

{
  "yaml.schemas": {
    "https://tikoci.github.io/restraml/routeros-app-yaml-schema.latest.json": "*.tikapp.yaml",
    "https://tikoci.github.io/restraml/routeros-app-yaml-store-schema.latest.json": "*.tikappstore.yaml"
  }
}

Use

.editor.json
URLs for better autocompletion at the cost of less strict validation.

Version History

  • 7.22: Initial /app support with basic service properties
  • 7.23beta2: New colon-style port format (
    :tcp
    /
    :udp
    suffix)
  • 7.23+: Additional service properties (
    devices
    ,
    expose
    ,
    secrets
    ,
    attach
    )

Common Mistakes

  • Assuming docker-compose compatibility — not all properties are supported, some behave differently
  • Using
    version:
    key
    — RouterOS ignores it; not needed
  • Mixing port format styles in a single entry — each port string must use ONE style exclusively
  • Uppercase env var names required in strict validation — use
    *.editor.json
    for mixed case
  • Forgetting the container package
    /app
    returns 404 without the
    container
    extra package
  • Using
    deploy:
    or
    resources:
    — not supported by RouterOS

Additional Resources