Docker Migration

A step-by-step guide to migrate your Docker workloads to niso. Most migrations take under 30 minutes.

Command mapping#

If you know Docker, you know niso. The commands map directly:

Dockerniso
Dockerfilemanifest.toml
docker buildniso pack
docker pushniso push
docker pullniso pull
docker runniso run / niso activate
docker psniso status / niso list
docker logsniso logs
docker execniso exec
docker stopniso deactivate
docker rmniso remove
docker inspectniso inspect / niso debug
docker statsniso top / niso stats
docker volume createniso volume create
docker network createniso net create
docker-compose.ymlstack.toml
docker-compose upniso stack up
docker-compose downniso stack down
Docker Hubniso.dev registry
Docker Desktopniso machine

Step 1: Dockerfile to manifest.toml#

Here is a typical Dockerfile and its niso equivalent:

Before: Dockerfile

dockerfile
FROM node:20-slimWORKDIR /appCOPY package*.json ./RUN npm ci --productionCOPY . .EXPOSE 3000HEALTHCHECK --interval=30s \  CMD curl -f http://localhost:3000/healthCMD ["node", "server.js"]

After: manifest.toml

toml
[package]name = "my-app"version = "1.0.0"[runtime]use = "nodejs:20"[binary]entrypoint = "node"args = ["server.js"][network]ports = ["3000:3000"][healthcheck]http = "http://127.0.0.1:3000/health"[isolation]preset = "server"
Tip
The niso package includes your app code and node_modules — all your dependencies are packaged. Only the Node.js runtime binary itself is on the host, bind-mounted into a fully isolated rootfs at activation. Result: ~10 MB package instead of ~470 MB Docker image, with the same isolation guarantees.

Step 2: docker-compose.yml to stack.toml#

Before: docker-compose.yml

yaml
version: "3.8"services:  api:    build: .    ports:      - "8080:8080"    depends_on:      db:        condition: service_healthy    environment:      DATABASE_URL: postgres://...  db:    image: postgres:16    volumes:      - pgdata:/var/lib/postgresql/data    environment:      POSTGRES_PASSWORD: secretvolumes:  pgdata:

After: stack.toml

toml
[stack]name = "my-platform"[[service]]name = "api"package = "my-api:1.0.0"ports = ["8080:8080"]depends_on = { db = "healthy" }[service.environment]DATABASE_URL = "postgres://..."[[service]]name = "db"package = "postgres:16"volumes = { pgdata = {  mount = "/data",  exclusive = true,} }[service.environment]POSTGRES_PASSWORD = "secret"

Step 3: Build and deploy#

bash
# Pack your application (replaces docker build)$ niso pack# Deploy the stack (replaces docker-compose up)$ niso stack up# Verify everything is running$ niso stack status  SERVICE   STATUS    HEALTH    UPTIME  api       active    healthy   5s  db        active    healthy   8s

Key differences#

No base images

Docker images include an OS (Ubuntu, Alpine). niso packages contain your app code + dependencies. The runtime binary is on the host, bind-mounted into an isolated rootfs.

No Dockerfile

No RUN commands, no multi-stage builds, no layer caching. manifest.toml declares what to run, not how to build it.

No daemon

Docker requires dockerd running at all times. niso uses systemd — the process manager already on your server.

No proxy processes

Docker runs a separate background process for every mapped port. niso doesn't — port mapping just works with nothing extra running.

Stricter defaults

Each service is fully isolated by default — own user, own filesystem, own network. Docker keeps several privileges and runs as root by default.

Volumes with access control

Docker volumes are accessible to any container. niso volumes require explicit grants per service.

What niso does not replace#

  • Kubernetes — niso doesn't have a scheduler, auto-scaler, or service mesh. For multi-host, use niso fleet.
  • CI/CD build systems — niso doesn't build your code. Build it with your existing toolchain, then pack.
  • Windows containers — niso is Linux-only.
  • OCI image compatibility — niso uses its own package format, not OCI images.

Common migration patterns#

Compiled binaries (Rust, Go, C++)

Simplest migration — just pack the binary:

bash
$ niso init --template rust# Edit manifest.toml$ niso pack --binary target/release/my-app$ niso install my-app-1.0.0-x86_64.niso$ niso activate my-app

Node.js applications

Your code and node_modules are packaged. Node.js runtime is on the host, isolated per service:

bash
$ niso init --template node# manifest.toml has [runtime] use = "nodejs:20"# [copy] includes server.js, package.json, node_modules/$ npm ci --production$ niso pack  # Package contains your code + node_modules  # Node.js runtime on host, bind-mounted into isolated rootfs$ niso install my-node-app-1.0.0-x86_64.niso$ niso activate my-node-app

Python applications

bash
$ niso init --template python# manifest.toml has [runtime] use = "python:3.12"$ pip install -r requirements.txt --target ./vendor$ niso pack$ niso activate my-python-app