diff --git a/README.md b/README.md
index c479d90..750f7a8 100644
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@ python3 -m demorepo [command] [options]
 ### run
 
 ```
-demorepo run [-h] [-t TARGETS] [-e ENV] [--reverse-targets] command
+demorepo run [-h] [-t TARGETS] [-e ENV] [--reverse-targets] [--stop-on-error] command
 ```
 
 Execute a shell command for all projects.
@@ -78,12 +78,13 @@ optional arguments:
                         The format is VAR_NAME=VAR_VALUE. Multiple env vars
                         can be specified.
   --reverse-targets     Reverse the dependency order for projects
+  --stop-on-error       Stops the execution if the command fails for a project
 ```
 
 ### run-stage
 
 ```
-demorepo stage [-h] [-e ENV] [-t TARGETS] [--reverse-targets] stage
+demorepo stage [-h] [-e ENV] [-t TARGETS] [--reverse-targets] [--stop-on-error] stage
 ```
 
 Run the specified stage in the global and local config files.
@@ -102,6 +103,7 @@ optional arguments:
                         stage, separated by blank spaces (use quotes around
                         the string).
   --reverse-targets     Reverse the dependency order for projects
+  --stop-on-error       Stops the execution if the stage fails for a project
 ```
 
 ### diff
diff --git a/src/demorepo/commands/command_run.py b/src/demorepo/commands/command_run.py
index f08edba..504024f 100644
--- a/src/demorepo/commands/command_run.py
+++ b/src/demorepo/commands/command_run.py
@@ -62,7 +62,7 @@ def _get_child_environ(env):
     return child_environ
 
 
-def _run_targets(projects, paths, targets, env, *, stage=None, command=None):
+def _run_targets(projects, paths, targets, env, stop_on_error, *, stage=None, command=None):
     errors = []
 
     # Get scripts from stage scripts or paste the command
@@ -85,6 +85,8 @@ def _run_targets(projects, paths, targets, env, *, stage=None, command=None):
 
     logger.info('')
 
+    # Interrupted captures the index in which the execution is interrupted
+    interrupted = -1
     for t, script in scripts.items():
 
         logger.info(strformat.hline)
@@ -112,6 +114,10 @@ def _run_targets(projects, paths, targets, env, *, stage=None, command=None):
 
         if p.returncode != 0:
             errors.append(t)
+            # Capture the index of the target
+            if stop_on_error:
+                interrupted = list(scripts.keys()).index(t)
+                break
 
         logger.info('')
 
@@ -121,16 +127,27 @@ def _run_targets(projects, paths, targets, env, *, stage=None, command=None):
     index = 0
     for t in scripts.keys():
         index += 1
+
+        # Color depending on the error
         msg = "DONE" if t not in errors else "ERROR"
         color = strformat.GREEN if msg == "DONE" else strformat.RED
+
+        # Color has a third option if interrupted
+        if interrupted != -1 and index > interrupted+1:
+            msg = "SKIPPED"
+            color = strformat.YELLOW
+
         logger.info("  {}. {} {}".format(index, t, msg), color=color)
 
     logger.info("")
-    color = strformat.GREEN if len(errors) == 0 else strformat.RED
-    logger.info("----- {} scripts runned, {} successful, {} errors -----\n".format(len(scripts),
-                                                                                   len(scripts)-len(errors), len(errors)), color=color)
+    if interrupted == -1:
+        color = strformat.GREEN if len(errors) == 0 else strformat.RED
+        logger.info("----- {} scripts runned, {} successful, {} errors -----\n".format(len(scripts),
+                                                                                       len(scripts)-len(errors), len(errors)), color=color)
+    else:
+        logger.info("----- Interrupted by failed {} -----\n".format(mode), color=strformat.YELLOW)
 
-    # Exit with error if needed
+# Exit with error if needed
     if len(errors) > 0:
         sys.exit(-1)
 
@@ -140,19 +157,21 @@ def stage(args):
     targets = args.get('targets', None)
     reverse_targets = args['reverse_targets']
     env = args.get('env')
+    stop_on_error = args['stop_on_error']
 
     projects = config.get_projects()
     dependencies = config.get_projects_dependencies()
     paths = config.get_projects_paths()
 
-    targets = get_targets(projects, dependencies, targets, reverse_targets)
-    _run_targets(projects, paths, targets, env, stage=stage)
+    targets = get_targets(projects, dependencies, targets, reverse_targets, stop_on_error)
+    _run_targets(projects, paths, targets, env, stop_on_error, stage=stage)
 
 
 def run(args):
     command = args['command']
     targets = args.get('targets', None)
     reverse_targets = args['reverse_targets']
+    stop_on_error = args['stop_on_error']
     env = args.get('env')
 
     projects = config.get_projects()
@@ -160,4 +179,4 @@ def run(args):
     paths = config.get_projects_paths()
 
     targets = get_targets(projects, dependencies, targets, reverse_targets)
-    _run_targets(projects, paths, targets, env, command=command)
+    _run_targets(projects, paths, targets, env, stop_on_error, command=command)
diff --git a/src/demorepo/parser/__init__.py b/src/demorepo/parser/__init__.py
index f1cbc97..61104d2 100644
--- a/src/demorepo/parser/__init__.py
+++ b/src/demorepo/parser/__init__.py
@@ -50,6 +50,8 @@ parser_stage.add_argument('-t', '--targets', help='A list of target project name
                           'separated by blank spaces (use quotes around the string).')
 parser_stage.add_argument('--reverse-targets', action='store_true',
                           help='Reverse the dependency order for projects')
+parser_stage.add_argument('--stop-on-error', action='store_true',
+                          help='Stops the execution if the stage fails for a project')
 
 #
 # demorepo run
@@ -68,6 +70,8 @@ parser_run.add_argument('-e', '--env', action='append',
 #                                    'target projects too.')
 parser_run.add_argument('--reverse-targets', action='store_true',
                         help='Reverse the dependency order for projects')
+parser_run.add_argument('--stop-on-error', action='store_true',
+                        help='Stops the execution if the command fails for a project')
 
 #
 # End commands

Stop stage/command when errors happen
Some stages should be able to define a short circuit strategy when a particular script fails.

Use Case: Specifically in deploy scripts with dependences, the script should stop to avoid resources being deployed when their dependencies failed.
diff --git a/src/tests/demorepo.yml b/src/tests/demorepo.yml
index 5d38913..eef7802 100644
--- a/src/tests/demorepo.yml
+++ b/src/tests/demorepo.yml
@@ -19,15 +19,15 @@ projects:
             - p2
 
 stages:
-  test-p2:
+  test-all:
     script: ./test.sh
     projects:
+      - p1
       - p2
 
-  test-all:
+  test-p2:
     script: ./test.sh
     projects:
-      - p1
       - p2
 
   test-all-p3-fails:
@@ -37,6 +37,13 @@ stages:
       - p2
       - p3
 
+  test-all-p1-interrupts:
+    script: ./fail.sh
+    projects:
+      - p1
+      - p2
+      - p3
+
   test-all-local-p1:
     script: ./deploy.sh
     projects:
diff --git a/src/tests/test_parser.py b/src/tests/test_parser.py
index c2ef98f..ff287f4 100644
--- a/src/tests/test_parser.py
+++ b/src/tests/test_parser.py
@@ -6,8 +6,8 @@ from demorepo import parser
 
 defaults = dict(silent=False, log_path=None, working_mode=None)
 lgc_defaults = dict(ci_tool='gitlab', ci_url=None)
-run_defaults = dict(targets=None, env=None, reverse_targets=False)
-stage_defaults = dict(targets=None, env=None, reverse_targets=False)
+run_defaults = dict(targets=None, env=None, reverse_targets=False, stop_on_error=False)
+stage_defaults = dict(targets=None, env=None, reverse_targets=False, stop_on_error=False)
 
 
 @pytest.mark.parametrize("argv,expected,exit", [
@@ -56,8 +56,9 @@ stage_defaults = dict(targets=None, env=None, reverse_targets=False)
     ),
     # run opts
     (
-        ['demorepo', 'run', 'ls', '--targets', 'target1', '--reverse-targets', '--env', 'cosa=1234'],
-        dict(defaults, working_mode='run', command='ls', targets='target1', reverse_targets=True, env=['cosa=1234']),
+        ['demorepo', 'run', 'ls', '--targets', 'target1', '--reverse-targets', '--stop-on-error', '--env', 'cosa=1234'],
+        dict(defaults, working_mode='run', command='ls', targets='target1',
+             reverse_targets=True, stop_on_error=True, env=['cosa=1234']),
         None,
     ),
     # stage required
@@ -74,9 +75,9 @@ stage_defaults = dict(targets=None, env=None, reverse_targets=False)
     ),
     # stage opts
     (
-        ['demorepo', 'stage', 'deploy', '--targets', 'target1', '--reverse-targets', '--env', 'cosa=1234'],
+        ['demorepo', 'stage', 'deploy', '--targets', 'target1', '--reverse-targets', '--stop-on-error', '--env', 'cosa=1234'],
         dict(defaults, working_mode='stage', stage='deploy',
-             targets='target1', reverse_targets=True, env=['cosa=1234']),
+             targets='target1', reverse_targets=True, stop_on_error=True, env=['cosa=1234']),
         None,
     ),
 ])
diff --git a/src/tests/test_stage.py b/src/tests/test_stage.py
index 82a5b12..b93a675 100644
--- a/src/tests/test_stage.py
+++ b/src/tests/test_stage.py
@@ -10,11 +10,12 @@ default_args = {
     'stage': 'test',
     'targets': None,
     'reverse_targets': False,
+    'stop_on_error': True,
     'recursive_deps': False
 }
 
 
-def test_run_global_all(setup):
+def test_run_all(setup):
 
     args = default_args.copy()
     args["stage"] = "test-all"
@@ -26,7 +27,7 @@ def test_run_global_all(setup):
     assert mock_dict['mock_subprocess_Popen'] == 2
 
 
-def test_run_global_all_filter(setup):
+def test_run_all_filter(setup):
 
     args = default_args.copy()
     args["stage"] = "test-all"
@@ -39,7 +40,7 @@ def test_run_global_all_filter(setup):
     assert mock_dict['mock_subprocess_Popen'] == 1
 
 
-def test_run_global_all_filter_empty(setup):
+def test_run_all_filter_empty(setup):
 
     args = default_args.copy()
     args["stage"] = "test-all"
@@ -80,6 +81,22 @@ def test_run_global_all_p3_fails(setup):
     assert mock_dict['mock_sys_exit'] == 1
 
 
+def test_run_all_p1_interrupts(setup):
+
+    args = default_args.copy()
+    args["stage"] = "test-all-p1-interrupts"
+
+    mock_dict['mock_subprocess_Popen'] = 0
+    mock_dict['mock_sys_exit'] = 0
+    setup.setattr(subprocess, 'Popen', mock_subprocess_Popen)
+    setup.setattr(sys, 'exit', mock_sys_exit)
+
+    commands.stage(args)
+
+    assert mock_dict['mock_subprocess_Popen'] == 1
+    assert mock_dict['mock_sys_exit'] == 1
+
+
 def test_run_all_local_p1(setup):
     # TODO: How can we really assert that this is really calling the local script?
     args = default_args.copy()

pip install -e .[dev]
parse_log_pytest
requirements.txt
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi==2025.1.31
chardet==3.0.4
-e git+https://github.com/demosense/demorepo.git@c5e8e938224a7cf1cdffe51bf8755cd4f103dd3d#egg=demorepo
gitdb==4.0.12
gitdb2==4.0.2
GitPython==2.1.9
idna==2.6
PyYAML==3.12
requests==2.18.4
smmap==5.0.2
urllib3==1.22

name: demorepo
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - chardet==3.0.4
      - gitdb==4.0.12
      - gitdb2==4.0.2
      - gitpython==2.1.9
      - idna==2.6
      - pyyaml==3.12
      - requests==2.18.4
      - smmap==5.0.2
      - urllib3==1.22
prefix: /opt/conda/envs/demorepo

src/tests/test_parser.py::test_parser[argv5-expected5-None] src/tests/test_parser.py::test_parser[argv7-expected7-None] src/tests/test_parser.py::test_parser[argv8-expected8-None] src/tests/test_parser.py::test_parser[argv10-expected10-None]
src/tests/test_stage.py::test_run_all src/tests/test_stage.py::test_run_all_filter src/tests/test_stage.py::test_run_all_filter_empty src/tests/test_stage.py::test_run_global_p2 src/tests/test_stage.py::test_run_global_all_p3_fails src/tests/test_stage.py::test_run_all_p1_interrupts src/tests/test_stage.py::test_run_all_local_p1
src/tests/test_parser.py::test_parser[argv0-expected0-None] src/tests/test_parser.py::test_parser[argv1-expected1-SystemExit] src/tests/test_parser.py::test_parser[argv2-expected2-None] src/tests/test_parser.py::test_parser[argv3-expected3-None] src/tests/test_parser.py::test_parser[argv4-expected4-SystemExit] src/tests/test_parser.py::test_parser[argv6-expected6-SystemExit] src/tests/test_parser.py::test_parser[argv9-expected9-SystemExit]
src/demorepo/parser/__init__.py README.md src/demorepo/commands/command_run.py
src/demorepo/parser/__init__.py README.md src/demorepo/commands/command_run.py