How to Run Multiple Macro Stacks in Parallel
To run multiple Macro stacks in parallel, export a unique MACRO_STACK_NAME environment variable for each instance before executing ./.cursor/stack.sh, which generates isolated Docker networks and Pulumi state files via the --stack-name argument assembled in .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 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 via the ${doppler_args[@]} array (lines 19‑22), which includes the stack identifier.
Layer 2: Argument Generation
.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 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
justfiletargets. - 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.
- Define unique stack names – Export
MACRO_STACK_NAMEwith a distinct value for each instance (e.g.,dev1,dev2,feature-test). - Adjust host ports – Export
MACRO_HTTP_PORTand other port variables to prevent binding collisions on the host machine. - Execute the stack script – Run
./.cursor/stack.shfor each configuration. The script backgrounds processes automatically when invoked with&.
# 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, each stack maintains its own infrastructure state, allowing independent updates and destruction.
Network Segregation
As implemented in 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 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:
# 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.shacts as the entry point that prepares binaries and delegates to the Just-based workflow..cursor/cloud-lib.shgenerates the critical--stack-nameargument from theMACRO_STACK_NAMEenvironment variable, ensuring Pulumi and Docker isolate resources.infra/preview/entrypoint.shexecutes the actual provisioning logic, creating prefixed networks and volumes for each stack instance.- Port conflicts are avoided by setting
MACRO_HTTP_PORTand related variables uniquely per stack. - Cleanup is scoped per stack using the same
MACRO_STACK_NAMEvariable withjust 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 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:
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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →