diff --git a/crates/configuration/src/global_settings.rs b/crates/configuration/src/global_settings.rs
index f5842069333e30ab7cb6bcbd1abd1f7053c930ae..95cee31decac6e7c73870be1f4532b58ca778c52 100644
--- a/crates/configuration/src/global_settings.rs
+++ b/crates/configuration/src/global_settings.rs
@@ -1,4 +1,10 @@
-use std::{error::Error, fmt::Display, net::IpAddr, str::FromStr};
+use std::{
+    error::Error,
+    fmt::Display,
+    net::IpAddr,
+    path::{Path, PathBuf},
+    str::FromStr,
+};
 
 use multiaddr::Multiaddr;
 use serde::{Deserialize, Serialize};
@@ -15,14 +21,24 @@ use crate::{
 /// Global settings applied to an entire network.
 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct GlobalSettings {
+    /// Global bootnodes to use (we will then add more)
     #[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)]
     bootnodes_addresses: Vec<Multiaddr>,
     // TODO: parse both case in zombienet node version to avoid renamed ?
+    /// Glocal spawn timeout
     #[serde(rename = "timeout")]
     network_spawn_timeout: Duration,
+    // TODO: not used yet
+    /// Node spawn timeout
     #[serde(default = "default_node_spawn_timeout")]
     node_spawn_timeout: Duration,
+    // TODO: not used yet
+    /// Local ip to use for construct the direct links
     local_ip: Option<IpAddr>,
+    /// Directory to use as base dir
+    /// Used to reuse the same files (database) from a previous run,
+    /// also note that we will override the content of some of those files.
+    base_dir: Option<PathBuf>,
 }
 
 impl GlobalSettings {
@@ -45,6 +61,12 @@ impl GlobalSettings {
     pub fn local_ip(&self) -> Option<&IpAddr> {
         self.local_ip.as_ref()
     }
+
+    /// Base directory to use (instead a random tmp one)
+    /// All the artifacts will be created in this directory.
+    pub fn base_dir(&self) -> Option<&Path> {
+        self.base_dir.as_deref()
+    }
 }
 
 /// A global settings builder, used to build [`GlobalSettings`] declaratively with fields validation.
@@ -61,6 +83,7 @@ impl Default for GlobalSettingsBuilder {
                 network_spawn_timeout: 1000,
                 node_spawn_timeout: 300,
                 local_ip: None,
+                base_dir: None,
             },
             errors: vec![],
         }
@@ -143,6 +166,17 @@ impl GlobalSettingsBuilder {
         }
     }
 
+    /// Set the directory to use as base (instead of a random tmp one).
+    pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self {
+        Self::transition(
+            GlobalSettings {
+                base_dir: Some(base_dir.into()),
+                ..self.config
+            },
+            self.errors,
+        )
+    }
+
     /// Seals the builder and returns a [`GlobalSettings`] if there are no validation errors, else returns errors.
     pub fn build(self) -> Result<GlobalSettings, Vec<anyhow::Error>> {
         if !self.errors.is_empty() {
@@ -171,6 +205,7 @@ mod tests {
             .with_network_spawn_timeout(600)
             .with_node_spawn_timeout(120)
             .with_local_ip("10.0.0.1")
+            .with_base_dir("/home/nonroot/mynetwork")
             .build()
             .unwrap();
 
@@ -192,6 +227,10 @@ mod tests {
                 .as_str(),
             "10.0.0.1"
         );
+        assert_eq!(
+            global_settings_config.base_dir().unwrap(),
+            Path::new("/home/nonroot/mynetwork")
+        );
     }
 
     #[test]
diff --git a/crates/examples/examples/common/lib.rs b/crates/examples/examples/common/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3fb23596a9d26e7f1f443d02d830f9e66e5fed1e
--- /dev/null
+++ b/crates/examples/examples/common/lib.rs
@@ -0,0 +1,33 @@
+use std::path::Path;
+
+use zombienet_sdk::{NetworkConfig, NetworkConfigBuilder};
+
+#[allow(dead_code)]
+pub fn small_network_config(
+    custom_base_dir: Option<&Path>,
+) -> Result<NetworkConfig, Vec<anyhow::Error>> {
+    // let config =
+    let builder = NetworkConfigBuilder::new()
+        .with_relaychain(|r| {
+            r.with_chain("rococo-local")
+                .with_default_command("polkadot")
+                .with_default_image("docker.io/parity/polkadot:latest")
+                .with_node(|node| node.with_name("alice"))
+                .with_node(|node| node.with_name("bob"))
+        })
+        .with_parachain(|p| {
+            p.with_id(2000).cumulus_based(true).with_collator(|n| {
+                n.with_name("collator")
+                    .with_command("polkadot-parachain")
+                    .with_image("docker.io/parity/polkadot-parachain:latest")
+            })
+        });
+
+    if let Some(base_dir) = custom_base_dir {
+        builder
+            .with_global_settings(|g| g.with_base_dir(base_dir))
+            .build()
+    } else {
+        builder.build()
+    }
+}
diff --git a/crates/examples/examples/small_network.rs b/crates/examples/examples/small_network_config.rs
similarity index 100%
rename from crates/examples/examples/small_network.rs
rename to crates/examples/examples/small_network_config.rs
diff --git a/crates/examples/examples/small_network_with_base_dir.rs b/crates/examples/examples/small_network_with_base_dir.rs
new file mode 100644
index 0000000000000000000000000000000000000000..296d61a00e4dc93e1dad7cb6fb092dcace13deac
--- /dev/null
+++ b/crates/examples/examples/small_network_with_base_dir.rs
@@ -0,0 +1,17 @@
+use std::path::Path;
+
+use zombienet_sdk::NetworkConfigExt;
+
+#[path = "./common/lib.rs"]
+mod common;
+
+#[tokio::main]
+async fn main() {
+    tracing_subscriber::fmt::init();
+    let config = common::small_network_config(Some(Path::new("/tmp/zombie-1"))).unwrap();
+    let _network = config.spawn_docker().await.unwrap();
+
+    // For now let just loop....
+    #[allow(clippy::empty_loop)]
+    loop {}
+}
diff --git a/crates/orchestrator/src/lib.rs b/crates/orchestrator/src/lib.rs
index 999d4ce78c6abc0ac772f8841f36fc1312c92018..14468f765f1c04a6c02c97a98025cbe0cec9f491 100644
--- a/crates/orchestrator/src/lib.rs
+++ b/crates/orchestrator/src/lib.rs
@@ -85,7 +85,14 @@ where
             })?;
 
         // create namespace
-        let ns = self.provider.create_namespace().await?;
+        let ns = if let Some(base_dir) = network_spec.global_settings.base_dir() {
+            self.provider
+                .create_namespace_with_base_dir(base_dir)
+                .await?
+        } else {
+            self.provider.create_namespace().await?
+        };
+
         info!("🧰 ns: {}", ns.name());
         info!("🧰 base_dir: {:?}", ns.base_dir());
 
@@ -118,7 +125,12 @@ where
             debug!("parachain chain-spec built!");
 
             // TODO: this need to be abstracted in a single call to generate_files.
-            scoped_fs.create_dir(para.id.to_string()).await?;
+            if network_spec.global_settings.base_dir().is_some() {
+                scoped_fs.create_dir_all(para.id.to_string()).await?;
+            } else {
+                scoped_fs.create_dir(para.id.to_string()).await?;
+            };
+
             // create wasm/state
             para.genesis_state
                 .build(
diff --git a/crates/provider/src/docker/namespace.rs b/crates/provider/src/docker/namespace.rs
index 06c030689dc85b973407be938a7f725a2a2c5c33..ddea343940426481dffbdc059bbf9fef3f9ed4ea 100644
--- a/crates/provider/src/docker/namespace.rs
+++ b/crates/provider/src/docker/namespace.rs
@@ -1,6 +1,6 @@
 use std::{
     collections::HashMap,
-    path::PathBuf,
+    path::{Path, PathBuf},
     sync::{Arc, Weak},
 };
 
@@ -8,7 +8,7 @@ use anyhow::anyhow;
 use async_trait::async_trait;
 use support::{constants::THIS_IS_A_BUG, fs::FileSystem};
 use tokio::sync::{Mutex, RwLock};
-use tracing::{debug, trace};
+use tracing::{debug, trace, warn};
 use uuid::Uuid;
 
 use super::{
@@ -52,10 +52,24 @@ where
         capabilities: &ProviderCapabilities,
         docker_client: &DockerClient,
         filesystem: &FS,
+        custom_base_dir: Option<&Path>,
     ) -> Result<Arc<Self>, ProviderError> {
         let name = format!("{}{}", NAMESPACE_PREFIX, Uuid::new_v4());
-        let base_dir = PathBuf::from_iter([tmp_dir, &PathBuf::from(&name)]);
-        filesystem.create_dir(&base_dir).await?;
+        let base_dir = if let Some(custom_base_dir) = custom_base_dir {
+            if !filesystem.exists(custom_base_dir).await {
+                filesystem.create_dir(custom_base_dir).await?;
+            } else {
+                warn!(
+                    "⚠️  Using and existing directory {} as base dir",
+                    custom_base_dir.to_string_lossy()
+                );
+            }
+            PathBuf::from(custom_base_dir)
+        } else {
+            let base_dir = PathBuf::from_iter([tmp_dir, &PathBuf::from(&name)]);
+            filesystem.create_dir(&base_dir).await?;
+            base_dir
+        };
 
         let namespace = Arc::new_cyclic(|weak| DockerNamespace {
             weak: weak.clone(),
diff --git a/crates/provider/src/docker/node.rs b/crates/provider/src/docker/node.rs
index 42af95f54af8979d444e3b0b93bbcf0ae22b6a06..4828b6e269ca75c2f7c5f332aad275950a9b3daa 100644
--- a/crates/provider/src/docker/node.rs
+++ b/crates/provider/src/docker/node.rs
@@ -91,10 +91,10 @@ where
         let log_path = base_dir.join("node.log");
 
         try_join!(
-            filesystem.create_dir(&config_dir),
-            filesystem.create_dir(&data_dir),
-            filesystem.create_dir(&relay_data_dir),
-            filesystem.create_dir(&scripts_dir),
+            filesystem.create_dir_all(&config_dir),
+            filesystem.create_dir_all(&data_dir),
+            filesystem.create_dir_all(&relay_data_dir),
+            filesystem.create_dir_all(&scripts_dir),
         )?;
 
         let node = Arc::new(DockerNode {
diff --git a/crates/provider/src/docker/provider.rs b/crates/provider/src/docker/provider.rs
index 5acd7c269ef0ebe084c9cca9c5fdb75c0c943351..6f72276e4b473edaf9c815fcffd64fc328b6d496 100644
--- a/crates/provider/src/docker/provider.rs
+++ b/crates/provider/src/docker/provider.rs
@@ -1,6 +1,6 @@
 use std::{
     collections::HashMap,
-    path::PathBuf,
+    path::{Path, PathBuf},
     sync::{Arc, Weak},
 };
 
@@ -84,6 +84,29 @@ where
             &self.capabilities,
             &self.docker_client,
             &self.filesystem,
+            None,
+        )
+        .await?;
+
+        self.namespaces
+            .write()
+            .await
+            .insert(namespace.name().to_string(), namespace.clone());
+
+        Ok(namespace)
+    }
+
+    async fn create_namespace_with_base_dir(
+        &self,
+        base_dir: &Path,
+    ) -> Result<DynNamespace, ProviderError> {
+        let namespace = DockerNamespace::new(
+            &self.weak,
+            &self.tmp_dir,
+            &self.capabilities,
+            &self.docker_client,
+            &self.filesystem,
+            Some(base_dir),
         )
         .await?;
 
diff --git a/crates/provider/src/kubernetes/namespace.rs b/crates/provider/src/kubernetes/namespace.rs
index ac43623888c40b24def288599fc5be35d156df26..c8792555efacfdfdc18c57e8d7489289cea7c4a1 100644
--- a/crates/provider/src/kubernetes/namespace.rs
+++ b/crates/provider/src/kubernetes/namespace.rs
@@ -1,7 +1,7 @@
 use std::{
     collections::{BTreeMap, HashMap},
     env,
-    path::PathBuf,
+    path::{Path, PathBuf},
     sync::{Arc, Weak},
 };
 
@@ -15,7 +15,7 @@ use k8s_openapi::{
 };
 use support::{constants::THIS_IS_A_BUG, fs::FileSystem, replacer::apply_replacements};
 use tokio::sync::{Mutex, RwLock};
-use tracing::{debug, trace};
+use tracing::{debug, trace, warn};
 use uuid::Uuid;
 
 use super::{client::KubernetesClient, node::KubernetesNode};
@@ -59,10 +59,24 @@ where
         capabilities: &ProviderCapabilities,
         k8s_client: &KubernetesClient,
         filesystem: &FS,
+        custom_base_dir: Option<&Path>,
     ) -> Result<Arc<Self>, ProviderError> {
         let name = format!("{}{}", NAMESPACE_PREFIX, Uuid::new_v4());
-        let base_dir = PathBuf::from_iter([tmp_dir, &PathBuf::from(&name)]);
-        filesystem.create_dir(&base_dir).await?;
+        let base_dir = if let Some(custom_base_dir) = custom_base_dir {
+            if !filesystem.exists(custom_base_dir).await {
+                filesystem.create_dir(custom_base_dir).await?;
+            } else {
+                warn!(
+                    "⚠️ Using and existing directory {} as base dir",
+                    custom_base_dir.to_string_lossy()
+                );
+            }
+            PathBuf::from(custom_base_dir)
+        } else {
+            let base_dir = PathBuf::from_iter([tmp_dir, &PathBuf::from(&name)]);
+            filesystem.create_dir(&base_dir).await?;
+            base_dir
+        };
 
         let namespace = Arc::new_cyclic(|weak| KubernetesNamespace {
             weak: weak.clone(),
diff --git a/crates/provider/src/kubernetes/provider.rs b/crates/provider/src/kubernetes/provider.rs
index 29cba8055cd36bc43df0c3c9ef99856bef816068..d54f9491fd96cb992ac524a364fcd03cb29eb950 100644
--- a/crates/provider/src/kubernetes/provider.rs
+++ b/crates/provider/src/kubernetes/provider.rs
@@ -1,6 +1,6 @@
 use std::{
     collections::HashMap,
-    path::PathBuf,
+    path::{Path, PathBuf},
     sync::{Arc, Weak},
 };
 
@@ -84,6 +84,29 @@ where
             &self.capabilities,
             &self.k8s_client,
             &self.filesystem,
+            None,
+        )
+        .await?;
+
+        self.namespaces
+            .write()
+            .await
+            .insert(namespace.name().to_string(), namespace.clone());
+
+        Ok(namespace)
+    }
+
+    async fn create_namespace_with_base_dir(
+        &self,
+        base_dir: &Path,
+    ) -> Result<DynNamespace, ProviderError> {
+        let namespace = KubernetesNamespace::new(
+            &self.weak,
+            &self.tmp_dir,
+            &self.capabilities,
+            &self.k8s_client,
+            &self.filesystem,
+            Some(base_dir),
         )
         .await?;
 
diff --git a/crates/provider/src/lib.rs b/crates/provider/src/lib.rs
index 0e0abec0a48e14572bdf8a132b448fba73d334e3..68563b85afacecf245677eb7d2082c951d48d4ed 100644
--- a/crates/provider/src/lib.rs
+++ b/crates/provider/src/lib.rs
@@ -122,6 +122,11 @@ pub trait Provider {
     async fn namespaces(&self) -> HashMap<String, DynNamespace>;
 
     async fn create_namespace(&self) -> Result<DynNamespace, ProviderError>;
+
+    async fn create_namespace_with_base_dir(
+        &self,
+        base_dir: &Path,
+    ) -> Result<DynNamespace, ProviderError>;
 }
 
 pub type DynProvider = Arc<dyn Provider + Send + Sync>;
diff --git a/crates/provider/src/native/namespace.rs b/crates/provider/src/native/namespace.rs
index ddefcc16c61ce3127c05d1a77f89f5d2cc20c16f..e8f82d659e4e64ede62c7ac8f70f2c70fa0b4d6b 100644
--- a/crates/provider/src/native/namespace.rs
+++ b/crates/provider/src/native/namespace.rs
@@ -1,6 +1,6 @@
 use std::{
     collections::HashMap,
-    path::PathBuf,
+    path::{Path, PathBuf},
     sync::{Arc, Weak},
 };
 
@@ -8,7 +8,7 @@ use anyhow::anyhow;
 use async_trait::async_trait;
 use support::fs::FileSystem;
 use tokio::sync::RwLock;
-use tracing::trace;
+use tracing::{trace, warn};
 use uuid::Uuid;
 
 use super::node::{NativeNode, NativeNodeOptions};
@@ -43,10 +43,24 @@ where
         tmp_dir: &PathBuf,
         capabilities: &ProviderCapabilities,
         filesystem: &FS,
+        custom_base_dir: Option<&Path>,
     ) -> Result<Arc<Self>, ProviderError> {
         let name = format!("{}{}", NAMESPACE_PREFIX, Uuid::new_v4());
-        let base_dir = PathBuf::from_iter([tmp_dir, &PathBuf::from(&name)]);
-        filesystem.create_dir(&base_dir).await?;
+        let base_dir = if let Some(custom_base_dir) = custom_base_dir {
+            if !filesystem.exists(custom_base_dir).await {
+                filesystem.create_dir(custom_base_dir).await?;
+            } else {
+                warn!(
+                    "⚠️ Using and existing directory {} as base dir",
+                    custom_base_dir.to_string_lossy()
+                );
+            }
+            PathBuf::from(custom_base_dir)
+        } else {
+            let base_dir = PathBuf::from_iter([tmp_dir, &PathBuf::from(&name)]);
+            filesystem.create_dir(&base_dir).await?;
+            base_dir
+        };
 
         Ok(Arc::new_cyclic(|weak| NativeNamespace {
             weak: weak.clone(),
diff --git a/crates/provider/src/native/provider.rs b/crates/provider/src/native/provider.rs
index 799c379b0e257dec59126db0e01e7bc6abef1bff..5e7c528ff5601e1e1a29198acd41a340f2db1df4 100644
--- a/crates/provider/src/native/provider.rs
+++ b/crates/provider/src/native/provider.rs
@@ -1,6 +1,6 @@
 use std::{
     collections::HashMap,
-    path::PathBuf,
+    path::{Path, PathBuf},
     sync::{Arc, Weak},
 };
 
@@ -83,6 +83,28 @@ where
             &self.tmp_dir,
             &self.capabilities,
             &self.filesystem,
+            None,
+        )
+        .await?;
+
+        self.namespaces
+            .write()
+            .await
+            .insert(namespace.name().to_string(), namespace.clone());
+
+        Ok(namespace)
+    }
+
+    async fn create_namespace_with_base_dir(
+        &self,
+        base_dir: &Path,
+    ) -> Result<DynNamespace, ProviderError> {
+        let namespace = NativeNamespace::new(
+            &self.weak,
+            &self.tmp_dir,
+            &self.capabilities,
+            &self.filesystem,
+            Some(base_dir),
         )
         .await?;