diff --git a/doc/example.md b/doc/example.md
index a046b3da9b4737e23146842c1c8a8ea517e1b3c0..369d19ba1b0a0a5e2c95d2945fe936e8da31a919 100644
--- a/doc/example.md
+++ b/doc/example.md
@@ -23,6 +23,19 @@ with derivations:
 - `//Charlie`
 - ...
 
+## Configuration
+
+It can be handful to use Gcli with a configuration file to avoid passing arguments on every command.
+
+```sh
+# show config commands
+gcli config
+# show where config file is stored
+gcli config where
+# save config to use gdev network for next commands
+gcli --network gdev config save
+```
+
 ## Commands
 
 ```sh
diff --git a/src/conf.rs b/src/conf.rs
index 89a4c93e72c7414294d2b1734d96341e0c355913..7b5afba8ca5ce5cf2085d2ffb21cb4fb0fb3fb47 100644
--- a/src/conf.rs
+++ b/src/conf.rs
@@ -5,8 +5,12 @@ const APP_NAME: &str = "gcli";
 
 #[derive(Serialize, Deserialize, Debug)]
 pub struct Config {
+	// duniter endpoint
 	pub duniter_endpoint: String,
+	// indexer endpoint
 	pub indexer_endpoint: String,
+	// user address
+	pub address: Option<AccountId>,
 }
 
 impl std::default::Default for Config {
@@ -14,6 +18,7 @@ impl std::default::Default for Config {
 		Self {
 			duniter_endpoint: String::from(data::LOCAL_DUNITER_ENDPOINT),
 			indexer_endpoint: String::from(data::LOCAL_INDEXER_ENDPOINT),
+			address: None,
 		}
 	}
 }
diff --git a/src/data.rs b/src/data.rs
index cb3091615631f82d7d761a764f80c44ce684537c..be67bec4881a9df1232adc10fa522c8f8df9d7cf 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -33,8 +33,6 @@ pub struct Data {
 	pub client: Option<Client>,
 	// graphql to duniter-indexer
 	pub indexer: Option<Indexer>,
-	// user address
-	pub address: Option<AccountId>,
 	// user keypair
 	pub keypair: Option<Pair>,
 	// user identity index
@@ -79,7 +77,7 @@ impl Data {
 		self.indexer.as_ref().expect("indexer is not set up")
 	}
 	pub fn address(&self) -> AccountId {
-		self.address.clone().expect("an address is needed")
+		self.cfg.address.clone().expect("an address is needed")
 	}
 	pub fn keypair(&self) -> Pair {
 		self.keypair.clone().expect("a keypair is needed")
@@ -99,6 +97,7 @@ impl Data {
 	// --- mutators ---
 	/// use arguments to overwrite config
 	pub fn overwrite_from_args(mut self) -> Self {
+		// network
 		if let Some(network) = self.args.network.clone() {
 			// a network was provided as arugment
 			match &network[..] {
@@ -131,40 +130,54 @@ impl Data {
 				}
 			}
 		}
+		// duniter endpoint
 		if let Some(duniter_endpoint) = self.args.url.clone() {
 			self.cfg.duniter_endpoint = duniter_endpoint;
 		}
+		// indexer endpoint
 		if let Some(indexer_endpoint) = self.args.indexer.clone() {
 			self.cfg.indexer_endpoint = indexer_endpoint
 		}
+		// secret
+		if self.args.secret.is_some() {
+			self = self.build_keypair();
+		}
+		// address
+		if self.args.address.is_some() {
+			self = self.build_address();
+		}
 		self
 	}
-	/// force an address if needed
+	/// ask user to input an address if needed
 	pub fn build_address(mut self) -> Self {
-		self.address = Some(
-			get_keys(
+		if self.cfg.address.is_none() {
+			self.cfg.address = Some(
+				get_keys(
+					self.args.secret_format,
+					&self.args.address,
+					&self.args.secret,
+					NeededKeys::Public,
+				)
+				.expect("needed")
+				.0
+				.expect("needed"),
+			);
+		}
+		self
+	}
+	/// ask user to input a keypair if needed
+	pub fn build_keypair(mut self) -> Self {
+		if self.keypair.is_none() {
+			let (address, keypair) = get_keys(
 				self.args.secret_format,
 				&self.args.address,
 				&self.args.secret,
-				NeededKeys::Public,
+				NeededKeys::Secret,
 			)
-			.expect("needed")
-			.0
-			.expect("needed"),
-		);
-		self
-	}
-	/// force a keypair if needed
-	pub fn build_keypair(mut self) -> Self {
-		let (address, keypair) = get_keys(
-			self.args.secret_format,
-			&self.args.address,
-			&self.args.secret,
-			NeededKeys::Secret,
-		)
-		.expect("needed");
-		self.address = address;
-		self.keypair = keypair;
+			.expect("needed");
+			self.cfg.address = address;
+			self.keypair = keypair;
+		}
 		self
 	}
 	/// build a client from url