# How to Run Multiple Macro Stacks in Parallel

> Learn how to run multiple macro stacks in parallel by exporting unique MACRO_STACK_NAME environment variables. This ensures isolated Docker networks and Pulumi state files for efficient parallel execution.

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: how-to-guide
- Published: 2026-08-21

---

**To run multiple Macro stacks in parallel, export a unique `MACRO_STACK_NAME` environment variable for each instance before executing [`./.cursor/stack.sh`](https://github.com/macro-inc/macro/blob/main/./.cursor/stack.sh), which generates isolated Docker networks and Pulumi state files via the `--stack-name` argument assembled in [`.cursor/cloud-lib.sh`](https://github.com/macro-inc/macro/blob/main/.cursor/cloud-lib.sh).**

The macro-inc/macro repository orchestrates its full development environment—databases, auxiliary services, and micro-services—through a unified **stack** abstraction managed by Pulumi. While the default `just stack up` command launches a single instance, the underlying scripts support running multiple Macro stacks in parallel by parameterizing the stack identifier, enabling isolated testing environments on a single machine.

## How the Stack Architecture Enables Parallel Execution

The Macro stack system uses a three-layer architecture that separates orchestration logic from resource provisioning. Understanding this flow clarifies how parallel instances avoid conflicts.

**Layer 1: Entry Point**  
[`.cursor/stack.sh`](https://github.com/macro-inc/macro/blob/main/.cursor/stack.sh) serves as the primary interface. It builds local binaries, prepares environment arguments through Doppler integration, and delegates to `just stack up`. Critically, it sources arguments from [`cloud-lib.sh`](https://github.com/macro-inc/macro/blob/main/cloud-lib.sh) via the `${doppler_args[@]}` array (lines 19‑22), which includes the stack identifier.

**Layer 2: Argument Generation**  
[`.cursor/cloud-lib.sh`](https://github.com/macro-inc/macro/blob/main/.cursor/cloud-lib.sh) contains the `stack_doppler_args` function that assembles the final command-line arguments for Pulumi. This function injects `--stack-name $MACRO_STACK_NAME` into the argument list (lines 235‑244), ensuring each invocation targets a distinct Pulumi state file and Docker project name.

**Layer 3: Resource Provisioning**  
[`infra/preview/entrypoint.sh`](https://github.com/macro-inc/macro/blob/main/infra/preview/entrypoint.sh) receives these arguments and invokes the Rust-based `xtask stack up` binary. This binary creates Docker networks, volumes, and containers prefixed with the stack name (lines 102‑106), providing complete resource isolation between instances.

## Prerequisites

Before launching parallel stacks, ensure your environment meets these requirements:

- **Docker Engine** and **Docker Compose** installed and running.
- **Doppler CLI** configured (optional, but the scripts reference Doppler for secrets management).
- The **Just** command runner installed to process the `justfile` targets.
- Sufficient system resources (RAM, CPU) to host multiple database and service instances simultaneously.

## Step-by-Step: Launching Multiple Isolated Stacks

Running parallel instances requires setting unique identifiers and optionally customizing exposed ports to avoid host-level binding conflicts.

1. **Define unique stack names** – Export `MACRO_STACK_NAME` with a distinct value for each instance (e.g., `dev1`, `dev2`, `feature-test`).
2. **Adjust host ports** – Export `MACRO_HTTP_PORT` and other port variables to prevent binding collisions on the host machine.
3. **Execute the stack script** – Run [`./.cursor/stack.sh`](https://github.com/macro-inc/macro/blob/main/./.cursor/stack.sh) for each configuration. The script backgrounds processes automatically when invoked with `&`.

```bash

# Build binaries once (shared across stacks)

./.cursor/stack.sh build_local_stack_binaries

# Launch Stack 1

export MACRO_STACK_NAME=dev1
export MACRO_HTTP_PORT=8081
./.cursor/stack.sh &
echo "Stack dev1 launching on http://localhost:8081"

# Launch Stack 2

export MACRO_STACK_NAME=dev2
export MACRO_HTTP_PORT=8082
./.cursor/stack.sh &
echo "Stack dev2 launching on http://localhost:8082"

```

Each process creates independent Docker networks (`macro-dev1`, `macro-dev2`) and volumes (`macro-postgres-dev1`, etc.), ensuring complete isolation.

## Understanding Resource Isolation Mechanisms

Parallel stacks do not share state due to distinct naming conventions enforced at the infrastructure level.

**Docker Project Isolation**  
The `docker compose` command receives the `--project-name` parameter derived from `MACRO_STACK_NAME`. This prefixes all container names, network names, and volume labels, preventing cross-stack interference.

**Pulumi State Separation**  
Pulumi stores stack state in files named after the `--stack-name` argument. By passing distinct names via [`cloud-lib.sh`](https://github.com/macro-inc/macro/blob/main/cloud-lib.sh), each stack maintains its own infrastructure state, allowing independent updates and destruction.

**Network Segregation**  
As implemented in [`infra/preview/entrypoint.sh`](https://github.com/macro-inc/macro/blob/main/infra/preview/entrypoint.sh), each stack creates a dedicated bridge network. Containers within one stack cannot communicate with another stack’s containers unless explicitly linked through external networks.

## Customizing Environment Variables for Each Stack

When running multiple instances, configure these environment variables before invoking the stack script:

| Variable | Purpose | Example |
|----------|---------|---------|
| `MACRO_STACK_NAME` | **Required.** Unique identifier for the stack. | `export MACRO_STACK_NAME=local-dev` |
| `MACRO_HTTP_PORT` | Host port mapping for the web interface. | `export MACRO_HTTP_PORT=8080` |
| `MACRO_POSTGRES_PORT` | Host port for PostgreSQL access. | `export MACRO_POSTGRES_PORT=5432` |
| `MACRO_REDIS_PORT` | Host port for Redis access. | `export MACRO_REDIS_PORT=6379` |

Setting these before [`./.cursor/stack.sh`](https://github.com/macro-inc/macro/blob/main/./.cursor/stack.sh) ensures the generated `doppler_args` array contains the correct overrides for that specific instance.

## Stopping and Cleaning Up Specific Stacks

To tear down a specific parallel stack without affecting others, export its identifier before running the down command:

```bash

# Stop only the dev1 stack

export MACRO_STACK_NAME=dev1
just stack down

# Verify removal

docker ps | grep macro-dev1  # Should return no results

```

The `just stack down` target invokes the same `xtask` binary with the `down` command, targeting only the resources tagged with the specified stack name.

## Summary

- **[`.cursor/stack.sh`](https://github.com/macro-inc/macro/blob/main/.cursor/stack.sh)** acts as the entry point that prepares binaries and delegates to the Just-based workflow.
- **[`.cursor/cloud-lib.sh`](https://github.com/macro-inc/macro/blob/main/.cursor/cloud-lib.sh)** generates the critical `--stack-name` argument from the `MACRO_STACK_NAME` environment variable, ensuring Pulumi and Docker isolate resources.
- **[`infra/preview/entrypoint.sh`](https://github.com/macro-inc/macro/blob/main/infra/preview/entrypoint.sh)** executes the actual provisioning logic, creating prefixed networks and volumes for each stack instance.
- **Port conflicts** are avoided by setting `MACRO_HTTP_PORT` and related variables uniquely per stack.
- **Cleanup** is scoped per stack using the same `MACRO_STACK_NAME` variable with `just stack down`.

## Frequently Asked Questions

### Can I run more than two Macro stacks simultaneously?

Yes. You can run as many stacks as your hardware resources allow. Each stack requires RAM for its PostgreSQL, Redis, and application containers, plus CPU cycles. Ensure you assign unique `MACRO_STACK_NAME` values and distinct host ports for each additional instance.

### Do I need separate Doppler projects for each parallel stack?

No. The Doppler configuration remains shared; isolation occurs through the `MACRO_STACK_NAME` variable passed to Pulumi. However, if you need stack-specific secrets, you can modify [`cloud-lib.sh`](https://github.com/macro-inc/macro/blob/main/cloud-lib.sh) to append additional Doppler project flags based on the stack identifier before line 235.

### How do I view logs for a specific stack?

Use Docker Compose commands with the project name filter. For a stack named `dev1`, run:

```bash
docker compose -p macro-dev1 logs -f

```

Alternatively, filter `docker ps` using `grep macro-dev1` to identify specific container IDs, then use `docker logs <container-id>`.

### Will parallel stacks conflict on internal service ports?

No. Internal container ports (e.g., Postgres 5432, Redis 6379) are isolated within each stack’s dedicated Docker network. Conflicts only occur on **host-bound ports** (the mappings you define with `MACRO_HTTP_PORT`, etc.), which is why you must specify unique host ports for each stack.