diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e5a4017c4..8708ba964 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -286,12 +286,12 @@ jobs:
           cargo build --all
           dora up
           dora list
-          dora start dataflow.yml --name ci-rust-test
+          dora start dataflow.yml --name ci-rust-test --detach
           sleep 10
           dora stop --name ci-rust-test  --grace-duration 5s
           cd ..
           dora build examples/rust-dataflow/dataflow_dynamic.yml
-          dora start examples/rust-dataflow/dataflow_dynamic.yml --name ci-rust-dynamic
+          dora start examples/rust-dataflow/dataflow_dynamic.yml --name ci-rust-dynamic --detach
           cargo run -p rust-dataflow-example-sink-dynamic
           sleep 5
           dora stop --name ci-rust-dynamic  --grace-duration 5s
@@ -315,11 +315,11 @@ jobs:
           cd test_python_project
           dora up
           dora list
-          dora start dataflow.yml --name ci-python-test
+          dora start dataflow.yml --name ci-python-test --detach
           sleep 10
           dora stop --name ci-python-test  --grace-duration 5s
           pip install "numpy<2.0.0" opencv-python
-          dora start ../examples/python-dataflow/dataflow_dynamic.yml --name ci-python-dynamic
+          dora start ../examples/python-dataflow/dataflow_dynamic.yml --name ci-python-dynamic --detach
           python ../examples/python-dataflow/plot_dynamic.py
           sleep 5
           dora stop --name ci-python-test  --grace-duration 5s
@@ -339,7 +339,7 @@ jobs:
           cmake -B build
           cmake --build build
           cmake --install build
-          dora start dataflow.yml --name ci-c-test
+          dora start dataflow.yml --name ci-c-test --detach
           sleep 10
           dora stop --name ci-c-test  --grace-duration 5s
           dora destroy
@@ -358,7 +358,7 @@ jobs:
           cmake -B build
           cmake --build build
           cmake --install build
-          dora start dataflow.yml --name ci-cxx-test
+          dora start dataflow.yml --name ci-cxx-test --detach
           sleep 10
           dora stop --name ci-cxx-test  --grace-duration 5s
           dora destroy
diff --git a/binaries/cli/src/main.rs b/binaries/cli/src/main.rs
index a746d0b82..25eeab233 100644
--- a/binaries/cli/src/main.rs
+++ b/binaries/cli/src/main.rs
@@ -117,6 +117,9 @@ enum Command {
         /// Attach to the dataflow and wait for its completion
         #[clap(long, action)]
         attach: bool,
+        /// Run the dataflow in background
+        #[clap(long, action)]
+        detach: bool,
         /// Enable hot reloading (Python only)
         #[clap(long, action)]
         hot_reload: bool,
@@ -341,6 +344,7 @@ fn run() -> eyre::Result<()> {
             coordinator_addr,
             coordinator_port,
             attach,
+            detach,
             hot_reload,
         } => {
             let dataflow_descriptor =
@@ -368,6 +372,16 @@ fn run() -> eyre::Result<()> {
                 &mut *session,
             )?;
 
+            let attach = match (attach, detach) {
+                (true, true) => eyre::bail!("both `--attach` and `--detach` are given"),
+                (true, false) => true,
+                (false, true) => false,
+                (false, false) => {
+                    println!("attaching to dataflow (use `--detach` to run in background)");
+                    true
+                }
+            };
+
             if attach {
                 attach_dataflow(
                     dataflow_descriptor,