Skip to content
sntnsPublic

About

Ship applications made of containers to any Docker host, as versioned CNAB bundles: Compose on one machine, Swarm on many.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

nemo

nemo

Ship applications made of containers to any Docker host, as versioned packages.
Compose on one machine, Swarm on many: from a laptop, a CI pipeline, or a site with no network.

Release Latest release License: Apache-2.0 CNAB 1.2

Getting started · Concepts · Use cases · Documentation · CLI reference


Your application is a dozen services described in compose files. Deploying it means building images, pushing them, copying files to servers, running docker compose up or docker stack deploy in the right order, passing the right secrets, and remembering what is running where. Every team ends up writing that glue, and every environment drifts from the others.

nemo replaces the glue. It turns each compose file into a bundle: one versioned package that carries the services, their images pinned by digest, and the installer that deploys them. Bundles are grouped into a stack, which says where they go and with what settings. nemo up brings the target to the stack: in dependency order, with live progress, and with a record of every run.

$ nemo up
shop · swarm · 4 installations

✔ database  install    2 services · 2 volumes · 1 network  9.4s
✔ broker    install    1 service · 1 volume · 1 network   6.1s
⠼ api       install    1/3 services ready  4.2s
    ✔ api-http    ▰▰       2/2   running
    ◌ api-worker  ▰▱       1/2   verifying
    ◌ api-cron    ▱        0/1   preparing
· frontend  install    waiting

Why nemo

  • Keep your compose files. A bundle is your compose file plus a few lines of metadata. Services, networks, volumes, configs, secrets, healthchecks and deploy settings keep their meaning.
  • One package per component, versioned. Images are pinned by digest inside the bundle: what you tested is exactly what runs, on every node.
  • Stacks instead of scripts. Declare the components and their dependencies once; nemo installs dependencies first, upgrades what is there, and uninstalls what you removed.
  • Anywhere Docker runs. Compose on a single host, Swarm on one to many nodes, reached through the local socket, ssh://, tcp:// or a docker context. One bundle runs on all of them unchanged.
  • No registry required. Copy bundles onto a disk, carry them to a site with no network, and nemo loads their images straight into the target's Docker.
  • Secrets stay where they are. Credentials are read from files, environment variables or commands when an action runs. nemo never stores them.
  • Know what runs. nemo status, nemo logs, and the history of every install, upgrade and uninstall, with its parameters and outputs.
  • Built on standards. Bundles are CNAB 1.2, stored in any OCI registry or OCI layout. Records follow the CNAB claims specification.

Install

Homebrew (macOS and Linux):

brew install sntns/tap/nemo

Linux packages, deb, rpm and apk, for amd64 and arm64:

gh release download -R sntns/nemo -p 'nemo_*_amd64.deb'
sudo apt install ./nemo_*_amd64.deb

Binaries for Linux, macOS and Windows, amd64 and arm64, are attached to every release.

Verify what you downloaded, against its provenance or the signed checksums:

gh attestation verify nemo_*_linux_amd64.tar.gz -R sntns/nemo
cosign verify-blob checksums.txt --bundle checksums.txt.sigstore.json \
  --certificate-identity-regexp '^https://github.com/sntns/nemo/.github/workflows/release.yml@' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

From source, with Go 1.26 or later:

go install github.com/sntns/nemo/cmd/nemo@latest

nemo talks to Docker through its API: the machine you run it on needs no Docker of its own when the target is remote, only the target runs Docker Engine. For shell completion, see nemo completion --help.

A first deployment in five minutes

The examples/hello stack has two bundles: nginx, which serves a page and a secret, and whoami, which depends on it. Build both bundles from their compose files, keep the stack, and bring it up on your local Docker:

git clone https://github.com/sntns/nemo && cd nemo

nemo bundle build -f examples/hello/nginx/compose.yaml \
  --image nginx:1.27-alpine=docker://nginx:1.27-alpine -o oci:examples/hello/build/nginx.oci
nemo bundle build -f examples/hello/whoami/compose.yaml \
  --image traefik/whoami:v1.10=docker://traefik/whoami:v1.10 -o oci:examples/hello/build/whoami.oci

nemo stack import examples/hello/stack.yaml
export HELLO_TOKEN=s3cret
nemo up
$ curl localhost:8080
hello from nemo in eu5
$ nemo status
hello · compose

✔ nginx   1.0.0  installed just now  1/1 services
✔ whoami  1.0.0  installed just now  1/1 services

Then change a setting and apply it, follow the logs, and remove everything:

nemo stack set --param region=eu6 && nemo up    # upgrades both installations
nemo logs nginx -f
nemo down --purge

The getting started guide walks through each step.

How it works

flowchart LR
    compose["compose.yaml<br/>+ x-nemo-bundle"] -- "nemo bundle build" --> bundle[("bundle<br/>registry or OCI layout")]
    bundle --> manifest["stack manifest<br/>target · parameters · credentials"]
    manifest -- "nemo up" --> nemo["nemo"]
    nemo -- "runs, on the target" --> gill["gill<br/>(installer container)"]
    gill -- "Compose or Swarm" --> app["services · networks<br/>volumes · configs · secrets"]
    nemo -. "keeps" .-> history[("history<br/>~/.nemo")]
Loading
  1. Build. nemo bundle build reads a compose file with an x-nemo-bundle block and makes a CNAB bundle: its ${VARIABLES} become parameters, its secrets become credentials, its images are pinned by digest, and gill, nemo's installer, becomes its invocation image. The bundle is written to a registry or to an OCI layout directory, with its images.
  2. Describe. A stack manifest lists the bundles to install on one target, the target's orchestrator and address, and the parameters and credential sources the bundles need.
  3. Deploy. nemo up orders the bundles by their dependencies, and for each one starts gill on the target with the Docker socket. gill applies the compose project with Compose or Swarm, labels everything it creates, and waits until the services are up. nemo shows the progress and records the run.

There is no server and no agent: nemo keeps its records on the machine it runs on, and gill only lives for the duration of an action. Read how it works for the details.

What you can do with it

You want to nemo gives you
Give every developer the whole platform on their machine One nemo up; nemo up api after rebuilding one component
Spin up a fresh environment for each pull request nemo up and nemo down --purge in CI, with --json records
Deploy to customer sites, factories, stores, edge boxes Bundles over ssh://, Compose on a single host
Run production on a Swarm cluster Rolling updates, versioned configs and secrets, verified convergence
Install where there is no network nemo bundle copy to a disk, images: load on the target
Ship your software to customers Versioned bundles they configure with nemo stack create

Each one is described in use cases.

Terraform and OpenTofu

The nemo provider, sntns/nemo on the Terraform Registry and the OpenTofu Registry, deploys a stack from Terraform or OpenTofu: a nemo_stack is its manifest, and each apply is a nemo up.

resource "nemo_stack" "shop" {
  name   = "shop"
  remote = "docker://registry.example.com/shop/{{ .Component }}:{{ .Version }}"
  target = { orchestrator = "swarm", host = "ssh://deploy@prod-1.example.com" }
  installations = [
    { name = "api", version = "1.4.0" },
    { name = "frontend", version = "1.4.0" },
  ]
}

The provider keeps the stack's records on its target: nemo status and nemo logs read it from any machine that imported the stack's manifest.

Documentation

Getting started Install nemo and deploy a first stack
Concepts Bundles, gill, targets, stacks, installations
How it works What happens when you build, deploy and remove
Use cases Development platforms, CI, edge, Swarm, offline sites, software vendors
Writing bundles From a compose file to a versioned bundle
Managing stacks Manifests, parameters, credentials, dependencies, up and down
Targets Compose or Swarm, remote Docker, registries or no registry, volume types
Continuous delivery Build, publish and deploy from a pipeline
Offline sites Deploy without network or registry
Reference Every command, the manifest, the bundle format, the environment
Comparison nemo next to Compose, Swarm stacks, Porter, Helm and scripts
Troubleshooting Common errors and how to read them

Contributing

Bug reports, ideas and pull requests are welcome: read CONTRIBUTING.md. Please report security issues privately, as described in SECURITY.md. Everyone taking part follows the code of conduct.

License

nemo is licensed under the Apache License 2.0. Copyright 2026 Sentiens SAS.

nemo is made and maintained by Sentiens (LinkedIn), by @ttnlmn.

The nemo logo is derived from the Go gopher, designed by Renée French and licensed under CC BY 4.0. See docs/assets.

About

Ship applications made of containers to any Docker host, as versioned CNAB bundles: Compose on one machine, Swarm on many.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages