Quick Start

Deploy your first application in 60 seconds. This guide walks through packaging a binary and running it as an isolated systemd service.

1. Initialize a project#

Create a new niso project with a manifest template for your stack:

bash
$ niso init --template rust  Created manifest.toml  Created src/main.rs

Available templates: rust, node, python, go. You can also start from an existing systemd service:

bash
$ niso init --from-systemd /etc/systemd/system/my-app.service

2. Edit the manifest#

The manifest.toml is the single source of truth for your package. Here is a minimal example for a Rust HTTP server:

manifest.toml
[package]name = "my-api"version = "1.0.0"[binary]entrypoint = "my-api"[healthcheck]http = "http://127.0.0.1:8080/health"[network]ports = ["8080:8080"][isolation]preset = "server"

3. Build and pack#

Build your application, then create a niso package:

bash
$ cargo build --release$ niso pack --binary target/release/my-api  my-api-1.0.0-x86_64.niso (8.2 MB)
Tip
The --binary flag overrides the entrypoint binary in the package. For Node.js or Python apps, omit it — your app code and dependencies (node_modules/, pip packages) are packed instead. The runtime interpreter is on the host, bind-mounted into an isolated rootfs at activation.

4. Install and activate#

bash
$ niso install my-api-1.0.0-x86_64.niso  Installed my-api 1.0.0$ niso activate my-api  Generated niso-my-api.service  Network: bridge niso-default, IP 10.99.0.2  Port: 8080 → 8080  Volume: data → /var/lib/niso/volumes/my-api-data  ✓ Service niso-my-api started

That is it. Your application is now running as an isolated systemd service — own user, own filesystem, own network. It cannot see the host or other services.

5. Verify#

bash
$ niso status my-api  my-api  1.0.0  active (running)  uptime 3s  mem 12MB$ niso logs my-api --follow  2026-04-12T10:00:01Z  INFO  Listening on 0.0.0.0:8080$ curl http://localhost:8080/health  {"status":"ok"}

6. Update and rollback#

Deploy a new version. niso keeps the previous version for instant rollback:

bash
# Deploy v1.1.0$ niso pack --binary target/release/my-api$ niso install my-api-1.1.0-x86_64.niso$ niso activate my-api 1.1.0# Something wrong? Instant rollback$ niso rollback my-api  Rolled back to 1.0.0  ✓ Service niso-my-api restarted

Node.js example#

For Node.js apps, your code and node_modules are packaged. The Node.js runtime itself is installed once on the host and bind-mounted into a fully isolated rootfs at activation time — the process sees a complete filesystem and cannot access the host.

manifest.toml
[package]name = "my-express-app"version = "1.0.0"[runtime]use = "nodejs:20"          # Runtime installed once on host[binary]entrypoint = "node"args = ["server.js"][copy]include = ["server.js", "package.json", "node_modules/"][healthcheck]http = "http://127.0.0.1:3000/health"[network]ports = ["3000:3000"][isolation]preset = "server"          # fully isolated[isolation.resources]memory_max = "512M"
bash
$ npm ci --production$ niso pack  my-express-app-1.0.0-x86_64.niso (12 MB)  # Contains: server.js + node_modules  # Node.js runtime: on host, bind-mounted into isolated rootfs
Full isolation, even with host runtimes
At activation, niso assembles a rootfs with your code, dependencies, and the runtime bind-mounted in. systemd's RootDirectory pivots the process into this rootfs — the host filesystem is invisible. The process cannot tell the runtime was bind-mounted.

Next steps#