Stack
$99/mo
Join waitlistFor single-node stack control
Run a lightweight Microstacks control plane for one node while defining stack dependencies without YAML configuration.
Included features
Mission Statement
Microstacks is a stack management system designed on the Unix philosophy of simplicity, modularity, and composability. It represents a stack as a hierarchical structure of dependency blocks, where each block can be deployed, managed, and scaled independently across multi cloud infrastructures. At its core, it virtualizes network, transport and application layer of TCP/IP stack to eliminate the service discovery requirement of a distributed system thereby eliminating the need network configuration to describe stack relationships, creating a new paradigm for stack management.
Swipe sideways to compare columns
Frameworks
MonolithicArchitecture
StaticStructure
CentralizedDeployment
VerticalScaling
Microstacks
ModularArchitecture
Orchestrators
MicroserviceArchitecture
DynamicStructure
DistributedDeployment
HorizontalScaling
A stack is an application organized as paths instead of loose service
names. Use map to place a GitHub project at a domain,
mount to attach frontend dependencies such as an API endpoint,
import to bring services into the root, and link to
connect those services to the blocks that need them.
# Map a GitHub project to a public domain $ stack map github.com/acme/frontend example.com Mapped github.com/acme/frontend at example.com # Mount the frontend API dependency under the domain $ stack mount myorg/api:1.4 example.com/api Mounted /api # Import shared services under the stack root $ stack import mysql:8 example.com/mysql Imported /mysql $ stack import redis:7 example.com/redis Imported /redis # Link services into the API address space $ stack link example.com/mysql example.com/api/mysql Linked /api/mysql to /mysql $ stack link example.com/redis example.com/api/redis Linked /api/redis to /redis # Inspect the live tree $ stack ls -r example.com TYPE PATH IMAGE VECTORS PORTS stack example.com github/acme/front — 443/tcp component example.com/api myorg/api:1.4 — 8080/tcp service example.com/mysql mysql:8 — 3306/tcp service example.com/redis redis:7 — 6379/tcp link example.com/api/mysql example.com/mysql — — link example.com/api/redis example.com/redis — —
Federated deployment does not require a new control system for every environment. SSH into a cloud node, run the same snap command, and the complete stack materializes from the shared model on that node.
# Open the AWS node console $ ssh ops@aws-use1.internal Connected to aws-use1.internal # Snap the complete stack onto AWS aws$ stack snap -r example.com Snapped example.com on aws-use1.internal
Vector scaling is the same operation from another node. SSH into a second cloud, run the same recursive snap, and Microstacks adds another runtime vector without changing the authored stack.
# Open the Azure node console $ ssh ops@azure-eastus.internal Connected to azure-eastus.internal # Run the same command to add a second vector azure$ stack snap -r example.com Snapped example.com on azure-eastus.internal
A complete WordPress stack mapped to local.wordpress.com. Map Caddy as the router, mount WordPress at the root path, import MySQL, and snap the full stack into a local deployment.
# Map Caddy as the router for the WordPress domain
$ stack map \
caddy:2 local.wordpress.com \
-- caddy reverse-proxy --from :80 --to http://127.0.0.1:80
# Mount WordPress at the root path
$ stack mount \
--env=WORDPRESS_DB_HOST=127.0.0.1:3306 \
--env=WORDPRESS_DB_USER=root \
--env=WORDPRESS_DB_PASSWORD=wordpress \
wordpress:7.0.2 local.wordpress.com/
# Import MySQL under /mysql
$ stack import \
--volume=mysql:/var/lib/mysql \
--env=MYSQL_DATABASE=wordpress \
--env=MYSQL_ROOT_PASSWORD=wordpress \
mysql:9.7.1 local.wordpress.com/mysql
# Snap the entire stack into a running local deployment
$ stack snap -r local.wordpress.comA local AI workspace mapped to open-webui.microstacks.com. Map Traefik as the router, mount Open WebUI, import Ollama, then run a root-level model block that pulls the model through the linked Ollama service.
# Map Traefik as the router for the Open WebUI domain
$ stack map \
--arguments=--providers.docker=true \
--label 'traefik.http.routers.default.rule=PathPrefix(`/`)' \
--label 'traefik.http.services.default.loadbalancer.server.url=http://127.0.0.1:80' \
traefik:v3.4 open-webui.microstacks.com
# Mount Open WebUI at the root path
$ stack mount \
--no-healthcheck \
--env OLLAMA_BASE_URL=http://127.0.0.1:11434 \
ghcr.io/open-webui/open-webui:v0.6.25 \
open-webui.microstacks.com/
# Import Ollama with its default server command
$ stack import \
--env GODEBUG="tlsmlkem=0" \
ollama/ollama:0.32.5 \
open-webui.microstacks.com/ollama
# Add a model job at the root path
$ stack import \
--no-restart \
--require 127.0.0.1:11434 \
ollama/ollama:0.32.5 \
open-webui.microstacks.com/model -- \
ollama pull qwen2.5:0.5b
# Link Ollama into the model address space
$ stack import \
open-webui.microstacks.com/ollama \
open-webui.microstacks.com/model/ollama
# Snap the Open WebUI stack
$ stack snap -r open-webui.microstacks.comA Redis replica set stack mapped to redis.rs.microstacks.com. Map Caddy as the router, mount RedisInsight, import Redis with instance-aware replica configuration, clone the Redis service block, and snap the primary plus replica vectors.
# Map Caddy as the router for the Redis replica set domain
$ stack map caddy:2 redis.rs.microstacks.com -- \
caddy reverse-proxy --from :80 --to 127.0.0.1:80
# Mount RedisInsight at the root path
$ stack mount \
redis/redisinsight:3.8.0 \
redis.rs.microstacks.com/
# Import Redis with instance-aware primary/replica configuration
$ stack import \
--env 'N=${INSTANCE#1}' \
redis:8.8.1 \
redis.rs.microstacks.com/redis -- \
redis-server \
'${N:+--replicaof}' '${N:+127.0.0.1}' '${N:+6379}'
# Clone the Redis service block under itself
$ stack import \
redis.rs.microstacks.com/redis \
redis.rs.microstacks.com/redis/redis
# Snap RedisInsight and scale the Redis replica vectors
$ stack snap -r redis.rs.microstacks.com
$ stack scale local.redis.rs.microstacks.com/redis=3A Redis cluster stack mapped to redis.cluster.microstacks.com. Map Caddy as the router, mount RedisInsight at the root path, import Redis with cluster ports, clone the Redis service block, and snap each vector into place.
# Map Caddy as the router for the Redis domain
$ stack map caddy:2 redis.cluster.microstacks.com -- \
caddy reverse-proxy --from :80 --to 127.0.0.1:80
# Mount RedisInsight at the root path
$ stack mount \
--env RI_REDIS_HOST=127.0.0.1 --env RI_REDIS_PORT=6379 \
redis/redisinsight:3.8.0 \
redis.cluster.microstacks.com/
# Import the first Redis cluster node
$ stack import \
--endpoint 16379/tcp \
redis:8.8.1 \
redis.cluster.microstacks.com/redis -- \
redis-server --cluster-enabled yes --appendonly yes --cluster-announce-ip \${BIND_ADDR}
# Clone the Redis service block under itself
$ stack import \
redis.cluster.microstacks.com/redis \
redis.cluster.microstacks.com/redis/redis
# Mount an admin job to create the Redis cluster
$ stack mount \
--no-restart \
--require 127.0.0.{1..6}:6379 \
redis:8.8.1 \
redis.cluster.microstacks.com/admin -- \
redis-cli --cluster create 127.0.0.{1..6}:6379 --cluster-replicas 1 --cluster-yes
# Link Redis into the admin address space
$ stack import \
redis.cluster.microstacks.com/redis \
redis.cluster.microstacks.com/admin/redis
# Snap RedisInsight and scale the Redis cluster vectors
$ stack snap -r redis.cluster.microstacks.com
$ stack scale local.redis.cluster.microstacks.com/redis=6A MongoDB replica set stack mapped to mongo.rs.microstacks.com. Reset the stack, map Caddy as the router, mount Compass Web, import MongoDB with replica set mode, clone the Mongo service block, and initialize the replica set from an admin job.
# Remove any existing MongoDB replica set stack
$ stack rm -r mongo.rs.microstacks.com
# Map Caddy as the router for the MongoDB replica set domain
$ stack map caddy:2 mongo.rs.microstacks.com -- \
caddy reverse-proxy --from :80 --to 127.0.0.1:80
# Mount Compass Web at the root path
$ stack mount \
--no-healthcheck \
--require 127.0.0.1:27017 \
--env 'CW_MONGO_URI=mongodb://1.localhost:27017,2.localhost:27017,3.localhost:27017/?replicaSet=rs0' \
haohanyang/compass-web \
mongo.rs.microstacks.com/
# Import MongoDB with replica set mode enabled
$ stack import \
mongo:8.3.7 \
mongo.rs.microstacks.com/mongo -- \
mongod --replSet rs0 --bind_ip '${INSTANCE}.localhost'
# Clone the MongoDB service block under itself
$ stack import \
mongo.rs.microstacks.com/mongo \
mongo.rs.microstacks.com/mongo/mongo
# Run an admin job to initialize the replica set
$ stack import \
--no-restart \
--require 127.0.0.{1..3}:27017 \
alpine/mongosh:latest \
mongo.rs.microstacks.com/admin -- \
mongosh --host 1.localhost --eval 'rs.initiate({_id:"rs0",members:[{_id:0,host:"1.localhost:27017"}]}); while (!db.hello().isWritablePrimary) { sleep(1000); }; rs.add("2.localhost:27017"); rs.add("3.localhost:27017"); rs.status()'
# Link MongoDB into the admin address space
$ stack import \
mongo.rs.microstacks.com/mongo \
mongo.rs.microstacks.com/admin/mongo
# Snap Compass Web and the MongoDB replica vectors
$ stack snap -r mongo.rs.microstacks.com
$ stack snap mongo.rs.microstacks.com/mongo
$ stack snap mongo.rs.microstacks.com/mongo
A sharded MongoDB cluster mapped to mongo.cluster.microstacks.com. Reset the stack, map Caddy as the router, mount Compass Web, define query, config, and shard blocks, wire their address spaces, and snap the cluster vectors.
# Remove any existing MongoDB cluster stack
$ stack rm -r mongo.cluster.microstacks.com
# Map Caddy as the router for the MongoDB cluster domain
$ stack map caddy:2 mongo.cluster.microstacks.com -- \
caddy reverse-proxy --from :80 --to 127.0.0.1:80
# Mount Compass Web at the root path
$ stack mount \
--no-healthcheck \
--require 127.0.0.1:27017 \
--env 'CW_MONGO_URI=mongodb://127.0.0.1:27017' \
--http-port 8080 \
haohanyang/compass-web \
mongo.cluster.microstacks.com/ -- \
compass-web --host 0.0.0.0
# Import the mongos query router
$ stack import \
--require 127.0.0.{1..3}:27019 \
--require 127.0.0.{1..2}:27018 \
--require 127.0.0.{1..2}:27028 \
--on-connect '127.0.0.1:27018=mongosh --host 127.0.0.1:27017 --quiet --eval "db.adminCommand({addShard:\"shard0/127.0.0.1:27018,127.0.0.2:27018\"})"' \
--on-connect '127.0.0.1:27028=mongosh --host 127.0.0.1:27017 --quiet --eval "db.adminCommand({addShard:\"shard1/127.0.0.1:27028,127.0.0.2:27028\"})"' \
mongo:8.3.7 \
mongo.cluster.microstacks.com/query -- \
mongos --configdb cfg/127.0.0.{1..3}:27019 --bind_ip '${INSTANCE}.microstacks'
# Import the config server replica set
$ stack import \
--local 27017/tcp \
--endpoint 27019/tcp \
--on-connect '127.0.0.1:27019=mongosh --host 127.0.0.1:27019 --quiet --eval "rs.initiate({_id:\"cfg\",configsvr:true,members:[{_id:0,host:\"127.0.0.1:27019\"}]})"' \
--on-connect ':27019=mongosh --host 127.0.0.1:27019 --quiet --eval "rs.add(\"${LOCALHOST}:${LOCALPORT}\")"' \
mongo:8.3.7 \
mongo.cluster.microstacks.com/query/config -- \
mongod --configsvr --replSet cfg --bind_ip '${INSTANCE}.microstacks'
# Import shard0
$ stack import \
--local 27017/tcp \
--endpoint 27018/tcp \
--on-connect '127.0.0.1:27018=mongosh --host 127.0.0.1:27018 --quiet --eval "rs.initiate({_id:\"shard0\",members:[{_id:0,host:\"127.0.0.1:27018\"}]})"' \
--on-connect ':27018=mongosh --host 127.0.0.1:27018 --quiet --eval "rs.add(\"${LOCALHOST}:${LOCALPORT}\")"' \
mongo:8.3.7 \
mongo.cluster.microstacks.com/query/shard0 -- \
mongod --shardsvr --replSet shard0 --bind_ip '${INSTANCE}.microstacks' --port 27018
# Import shard1
$ stack import \
--local 27017/tcp \
--endpoint 27028/tcp \
--on-connect '127.0.0.1:27028=mongosh --host 127.0.0.1:27028 --quiet --eval "rs.initiate({_id:\"shard1\",members:[{_id:0,host:\"127.0.0.1:27028\"}]})"' \
--on-connect ':27028=mongosh --host 127.0.0.1:27028 --quiet --eval "rs.add(\"${LOCALHOST}:${LOCALPORT}\")"' \
mongo:8.3.7 \
mongo.cluster.microstacks.com/query/shard1 -- \
mongod --shardsvr --replSet shard1 --bind_ip '${INSTANCE}.microstacks' --port 27028
# Link query, config, and shard address spaces
$ stack import mongo.cluster.microstacks.com/query mongo.cluster.microstacks.com/query/query
$ stack import mongo.cluster.microstacks.com/query/config mongo.cluster.microstacks.com/query/config/config
$ stack import mongo.cluster.microstacks.com/query/shard0 mongo.cluster.microstacks.com/query/config/shard0
$ stack import mongo.cluster.microstacks.com/query/shard1 mongo.cluster.microstacks.com/query/config/shard1
$ stack import mongo.cluster.microstacks.com/query/shard0 mongo.cluster.microstacks.com/query/shard0/shard0
$ stack import mongo.cluster.microstacks.com/query/config mongo.cluster.microstacks.com/query/shard0/config
$ stack import mongo.cluster.microstacks.com/query/shard1 mongo.cluster.microstacks.com/query/shard1/shard1
$ stack import mongo.cluster.microstacks.com/query/config mongo.cluster.microstacks.com/query/shard1/config
# Snap the MongoDB cluster vectors
$ stack snap -r mongo.cluster.microstacks.com
$ stack snap mongo.cluster.microstacks.com/query/config{,,}
$ stack snap mongo.cluster.microstacks.com/query/shard{0,1}The same model is available from code. You can define blocks, mount paths, import services, and snap vectors programmatically, then version and test those changes like the rest of your application.
package main import ( "github.com/microstacks/stack" "github.com/microstacks/stack/block" "github.com/microstacks/stack/vector" ) func main() { hub, _ := stack.Hub("https://example.com") gw, _ := hub.Gateway("example.com") root, _ := gw.Root() // Define a block — same fields as `stack import`. api := block.New("myorg/api:1.4", block.Kind(block.SERVICE), block.Env("DB_URL", "postgres://db/app"), block.Endpoint(8080, "tcp"), ) // Mount at /api (like `stack mount`). root.Mount(api, "/api") // Place vectors close to users in two regions. api.Snap(vector.Node{Address: "ssh://ops@edge-fra1"}) api.Snap(vector.Node{Address: "ssh://ops@edge-sin1"}) }
self hosted
Run Microstacks yourself, or upgrade to a managed cluster when you want hosted control plane operations.
DownloadStack
$99/mo
Join waitlistFor single-node stack control
Run a lightweight Microstacks control plane for one node while defining stack dependencies without YAML configuration.
Included features
Snap
$299/mo
Join waitlistFor resilient single-cloud stacks
Run a three-node cluster control plane for production stack management in a single cloud environment.
Everything in Stack, plus
Scale
$499/mo
Join waitlistFor federated multi-cloud stacks
Run a five-node cluster control plane for federated deployment and vector scaling across multiple clouds.
Everything in Snap, plus