diff --git a/cfg/tarantool_silverbox_cfg.c b/cfg/tarantool_silverbox_cfg.c
index 415a6fd25fcca7b10c62f80f24f5c43e9cdae850..caf93de716273b012481883fad04077c67807b05 100644
--- a/cfg/tarantool_silverbox_cfg.c
+++ b/cfg/tarantool_silverbox_cfg.c
@@ -78,8 +78,9 @@ acceptDefault_name__namespace(tarantool_cfg_namespace *c) {
 
 static int
 acceptDefault_name__namespace__index(tarantool_cfg_namespace_index *c) {
-	c->type = strdup("HASH");
+	c->type = strdup("");
 	if (c->type == NULL) return CNF_NOMEMORY;
+	c->unique = -1;
 	c->key_field = NULL;
 	return 0;
 }
@@ -87,7 +88,7 @@ acceptDefault_name__namespace__index(tarantool_cfg_namespace_index *c) {
 static int
 acceptDefault_name__namespace__index__key_field(tarantool_cfg_namespace_index_key_field *c) {
 	c->fieldno = -1;
-	c->type = strdup("NUM");
+	c->type = strdup("");
 	if (c->type == NULL) return CNF_NOMEMORY;
 	return 0;
 }
@@ -208,6 +209,11 @@ static NameAtom _name__namespace__index__type[] = {
 	{ "index", -1, _name__namespace__index__type + 2 },
 	{ "type", -1, NULL }
 };
+static NameAtom _name__namespace__index__unique[] = {
+	{ "namespace", -1, _name__namespace__index__unique + 1 },
+	{ "index", -1, _name__namespace__index__unique + 2 },
+	{ "unique", -1, NULL }
+};
 static NameAtom _name__namespace__index__key_field__fieldno[] = {
 	{ "namespace", -1, _name__namespace__index__key_field__fieldno + 1 },
 	{ "index", -1, _name__namespace__index__key_field__fieldno + 2 },
@@ -617,6 +623,19 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) {
 		 if (opt->paramValue.stringval && c->namespace[opt->name->index]->index[opt->name->next->index]->type == NULL)
 			return CNF_NOMEMORY;
 	}
+	else if ( cmpNameAtoms( opt->name, _name__namespace__index__unique) ) {
+		if (opt->paramType != numberType )
+			return CNF_WRONGTYPE;
+		ARRAYALLOC(c->namespace, opt->name->index + 1, _name__namespace);
+		ARRAYALLOC(c->namespace[opt->name->index]->index, opt->name->next->index + 1, _name__namespace__index);
+		errno = 0;
+		long int i32 = strtol(opt->paramValue.numberval, NULL, 10);
+		if (i32 == 0 && errno == EINVAL)
+			return CNF_WRONGINT;
+		if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE)
+			return CNF_WRONGRANGE;
+		c->namespace[opt->name->index]->index[opt->name->next->index]->unique = i32;
+	}
 	else if ( cmpNameAtoms( opt->name, _name__namespace__index__key_field__fieldno) ) {
 		if (opt->paramType != numberType )
 			return CNF_WRONGTYPE;
@@ -777,6 +796,7 @@ typedef enum IteratorState {
 	S_name__namespace__estimated_rows,
 	S_name__namespace__index,
 	S_name__namespace__index__type,
+	S_name__namespace__index__unique,
 	S_name__namespace__index__key_field,
 	S_name__namespace__index__key_field__fieldno,
 	S_name__namespace__index__key_field__type,
@@ -1169,6 +1189,7 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char
 		case S_name__namespace__estimated_rows:
 		case S_name__namespace__index:
 		case S_name__namespace__index__type:
+		case S_name__namespace__index__unique:
 		case S_name__namespace__index__key_field:
 		case S_name__namespace__index__key_field__fieldno:
 		case S_name__namespace__index__key_field__type:
@@ -1211,6 +1232,7 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char
 					case S_name__namespace__index:
 						i->state = S_name__namespace__index;
 					case S_name__namespace__index__type:
+					case S_name__namespace__index__unique:
 					case S_name__namespace__index__key_field:
 					case S_name__namespace__index__key_field__fieldno:
 					case S_name__namespace__index__key_field__type:
@@ -1225,6 +1247,17 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char
 										return NULL;
 									}
 									snprintf(buf, PRINTBUFLEN-1, "namespace[%d].index[%d].type", i->idx_name__namespace, i->idx_name__namespace__index);
+									i->state = S_name__namespace__index__unique;
+									return buf;
+								case S_name__namespace__index__unique:
+									*v = malloc(32);
+									if (*v == NULL) {
+										free(i);
+										out_warning(CNF_NOMEMORY, "No memory to output value");
+										return NULL;
+									}
+									sprintf(*v, "%"PRId32, c->namespace[i->idx_name__namespace]->index[i->idx_name__namespace__index]->unique);
+									snprintf(buf, PRINTBUFLEN-1, "namespace[%d].index[%d].unique", i->idx_name__namespace, i->idx_name__namespace__index);
 									i->state = S_name__namespace__index__key_field;
 									return buf;
 								case S_name__namespace__index__key_field:
diff --git a/cfg/tarantool_silverbox_cfg.cfg b/cfg/tarantool_silverbox_cfg.cfg
index d64f2b1249ac3f187f47a58bbc38fb8900a9b5bc..8a3668cdc5940f96f0a7727c0b2e2732d162c9a3 100644
--- a/cfg/tarantool_silverbox_cfg.cfg
+++ b/cfg/tarantool_silverbox_cfg.cfg
@@ -108,11 +108,12 @@ namespace = [
         estimated_rows = 0
         index = [
             {
-                type = "HASH"
+                type = ""
+                unique = -1
                 key_field = [
                     {
                         fieldno = -1
-                        type = "NUM"
+                        type = ""
                     }
                 ]
             }
diff --git a/cfg/tarantool_silverbox_cfg.cfg_tmpl b/cfg/tarantool_silverbox_cfg.cfg_tmpl
index 22ced2c366626b15e2327312b72ec3db847d6c64..264a62d751a3ac9f7acd952d9559e93a789b72e8 100644
--- a/cfg/tarantool_silverbox_cfg.cfg_tmpl
+++ b/cfg/tarantool_silverbox_cfg.cfg_tmpl
@@ -107,10 +107,11 @@ namespace = [
   cardinality = -1
   estimated_rows = 0
   index = [
-    type = "HASH"
+    type = ""
+    unique = -1
     key_field = [
       fieldno = -1
-      type = "NUM"
+      type = ""
     ]
   ]
 ]
diff --git a/cfg/tarantool_silverbox_cfg.h b/cfg/tarantool_silverbox_cfg.h
index 9513e73a99b39298236438e94f3891428516e245..b548b064cce9a9516066f82b2cf2916e93e6d90b 100644
--- a/cfg/tarantool_silverbox_cfg.h
+++ b/cfg/tarantool_silverbox_cfg.h
@@ -15,6 +15,7 @@ typedef struct tarantool_cfg_namespace_index_key_field {
 
 typedef struct tarantool_cfg_namespace_index {
 	char*	type;
+	int32_t	unique;
 	tarantool_cfg_namespace_index_key_field**	key_field;
 } tarantool_cfg_namespace_index;
 
diff --git a/mod/silverbox/box.c b/mod/silverbox/box.c
index 2c601f687d90760c03ab216cdf2be855ce20d56a..f65dd87702635652528e3e905c27e64d1f46d621 100644
--- a/mod/silverbox/box.c
+++ b/mod/silverbox/box.c
@@ -205,10 +205,12 @@ tree_index_member_compare(struct tree_index_member *member_a, struct tree_index_
 	if (member_b->tuple == NULL)
 		return 2;
 
-	if (member_a->tuple > member_b->tuple)
-		return 3;
-	else if (member_a->tuple < member_b->tuple)
-		return -3;
+	if (index->unique == false) {
+		if (member_a->tuple > member_b->tuple)
+			return 3;
+		else if (member_a->tuple < member_b->tuple)
+			return -3;
+	}
 
 	return 0;
 }
@@ -325,7 +327,7 @@ tuple_txn_ref(struct box_txn *txn, struct box_tuple *tuple)
 }
 
 static struct box_tuple *
-uniq_find_by_tuple(struct index *self, struct box_tuple *tuple)
+index_find_hash_by_tuple(struct index *self, struct box_tuple *tuple)
 {
 	void *key = tuple_field(tuple, self->key_field->fieldno);
 	if (key == NULL)
@@ -432,6 +434,22 @@ alloc_search_pattern(struct index *index, int key_cardinality, void *key)
 	return pattern;
 }
 
+static struct box_tuple *
+index_find_tree(struct index *self, void *key)
+{
+	struct tree_index_member *member = (struct tree_index_member *)key;
+
+	return sptree_str_t_find(self->idx.tree, member);
+}
+
+static struct box_tuple *
+index_find_tree_by_tuple(struct index *self, struct box_tuple *tuple)
+{
+	struct tree_index_member *member = tuple2tree_index_member(self, tuple, NULL);
+
+	return self->find(self, member);
+}
+
 static void
 index_remove_hash_num(struct index *self, struct box_tuple *tuple)
 {
@@ -554,7 +572,7 @@ validate_indeces(struct box_txn *txn)
 				if (!field_is_num(field))
 					box_raise(ERR_CODE_ILLEGAL_PARAMS, "field must be NUM");
 			}
-			if (index->type == TREE)
+			if (index->type == TREE && index->unique == false)
 				/* Don't check non unique indexes */
 				continue;
 
@@ -1496,6 +1514,14 @@ custom_init(void)
 
 			index->search_pattern = palloc(eter_pool, SIZEOF_TREE_INDEX_MEMBER(index));
 
+			if (cfg.namespace[i]->index[j]->unique == 0)
+				index->unique = false;
+			else if (cfg.namespace[i]->index[j]->unique == 1)
+				index->unique = true;
+			else
+				panic("(namespace = %" PRIu32 " index = %" PRIu32 ") "
+				      "unique property is undefined", i, j);
+
 			if (strcmp(cfg.namespace[i]->index[j]->type, "HASH") == 0) {
 				if (index->key_cardinality != 1)
 					panic("(namespace = %" PRIu32 " index = %" PRIu32 ") "
@@ -1504,9 +1530,13 @@ custom_init(void)
 				index->enabled = true;
 				index->type = HASH;
 
+				if (index->unique == false)
+					panic("(namespace = %" PRIu32 " index = %" PRIu32 ") "
+					      "hash index must be unique", i, j);
+
 				if (index->key_field->type == NUM) {
 					index->find = index_find_hash_num;
-					index->find_by_tuple = uniq_find_by_tuple;
+					index->find_by_tuple = index_find_hash_by_tuple;
 					index->remove = index_remove_hash_num;
 					index->replace = index_replace_hash_num;
 					index->namespace = &namespace[i];
@@ -1517,7 +1547,7 @@ custom_init(void)
 							  estimated_rows);
 				} else {
 					index->find = index_find_hash_str;
-					index->find_by_tuple = uniq_find_by_tuple;
+					index->find_by_tuple = index_find_hash_by_tuple;
 					index->remove = index_remove_hash_str;
 					index->replace = index_replace_hash_str;
 					index->namespace = &namespace[i];
@@ -1531,16 +1561,15 @@ custom_init(void)
 				index->enabled = false;
 				index->type = TREE;
 
-				index->find = NULL;
-				index->find_by_tuple = NULL;
+				index->find = index_find_tree;
+				index->find_by_tuple = index_find_tree_by_tuple;
 				index->remove = index_remove_tree_str;
 				index->replace = index_replace_tree_str;
 				index->iterator_init = index_iterator_init_tree_str;
 				index->iterator_next = index_iterator_next_tree_str;
 				index->namespace = &namespace[i];
 
-				index->idx.tree =
-					palloc(eter_pool, sizeof(*index->idx.tree));
+				index->idx.tree = palloc(eter_pool, sizeof(*index->idx.tree));
 			} else
 				panic("namespace = %" PRIu32 " index = %" PRIu32 ") "
 				      "unknown index type `%s'",
@@ -1666,7 +1695,7 @@ build_indexes(void)
 				}
 
 				m = (struct tree_index_member *)
-				    ((char *)member + i * SIZEOF_TREE_INDEX_MEMBER(index));
+					((char *)member + i * SIZEOF_TREE_INDEX_MEMBER(index));
 
 				tuple2tree_index_member(index,
 							kh_value(namespace[n].index[0].idx.hash,
diff --git a/mod/silverbox/box.h b/mod/silverbox/box.h
index 7b5228cb3f06f1109d1b0b4b9b55d405d3716a27..2c3a51ce4ca4dc9416cab649ee96c809b567fb48 100644
--- a/mod/silverbox/box.h
+++ b/mod/silverbox/box.h
@@ -64,6 +64,8 @@ SPTREE_DEF(str_t, realloc);
 struct index {
 	bool enabled;
 
+	bool unique;
+
 	struct box_tuple *(*find) (struct index * index, void *key);	/* only for unique lookups */
 	struct box_tuple *(*find_by_tuple) (struct index * index, struct box_tuple * pattern);
 	void (*remove) (struct index * index, struct box_tuple *);
diff --git a/mod/silverbox/box_cfg.cfg_tmpl b/mod/silverbox/box_cfg.cfg_tmpl
index a5200a53ce7758c773a710493c097a12dad1e57a..54ca6ca3eeca6bad879afedf460f059f98f45907 100644
--- a/mod/silverbox/box_cfg.cfg_tmpl
+++ b/mod/silverbox/box_cfg.cfg_tmpl
@@ -56,10 +56,11 @@ namespace = [
   cardinality = -1
   estimated_rows = 0
   index = [
-    type = "HASH"
+    type = ""
+    unique = -1
     key_field = [
       fieldno = -1
-      type = "NUM"
+      type = ""
     ]
   ]
 ]
diff --git a/mod/silverbox/t/box.pl b/mod/silverbox/t/box.pl
index 367edf79d3ed6b379a1ce29725aab33537f4baeb..29a16aad64841609eeeed5a7af525498fc481481 100644
--- a/mod/silverbox/t/box.pl
+++ b/mod/silverbox/t/box.pl
@@ -10,7 +10,7 @@ use lib "$Bin";
 use TBox ();
 use Carp qw/confess/;
 
-use Test::More tests => 182;
+use Test::More tests => 201;
 use Test::Exception;
 
 local $SIG{__DIE__} = \&confess;
@@ -459,3 +459,57 @@ my @tuple_bad = (13, 'mail.ru', '123');
 cleanup $tuple_bad[0];
 throws_ok sub { $box->Insert(@tuple_bad) }, qr/Illegal parametrs/, "index_constains/bad_field_type";
 
+
+## Check unique tree index
+sub def_param_unique {
+    my $format = 'l&&&';
+    return { servers => $server,
+             namespaces => [ {
+                 indexes => [ {
+		     index_name   => 'id',
+		     keys         => [0],
+		 }, {
+                     index_name   => 'email',
+                     keys         => [1],
+                 }, {
+                     index_name   => 'firstname',
+                     keys         => [2],
+                 }, {
+                     index_name   => 'lastname',
+                     keys         => [3],
+                 } , {
+		     index_name   => 'fullname',
+		     keys         => [2, 3]
+		 } ],
+                 namespace     => 27,
+                 format        => $format,
+                 default_index => 'id',
+             } ]}
+}
+
+$box = MR::SilverBox->new(def_param_unique);
+ok $box->isa('MR::SilverBox'), 'connect';
+
+my $tuples = [ [1, 'rtokarev@corp.mail.ru', 'Roman', 'Tokarev'],
+	       [2, 'vostrikov@corp.mail.ru', 'Yuri', 'Vostrikov'],
+	       [3, 'aleinikov@corp.mail.ru', 'Roman', 'Aleinikov'],
+	       [4, 'roman.s.tokarev@gmail.com', 'Roman', 'Tokarev'],
+	       [5, 'vostrikov@corp.mail.ru', 'delamon', 'delamon'] ];
+
+foreach my $tuple (@$tuples) {
+	cleanup $tuple->[0];
+}
+
+foreach my $tuple (@$tuples) {
+	if ($tuple == $tuples->[-1] || $tuple == $tuples->[-2]) {
+		throws_ok sub { $box->Insert(@$tuple) }, qr/Index violation/, "unique_tree_index/insert \'$tuple->[0]\'";
+	} else {
+		ok $box->Insert(@$tuple), "unique_tree_index/insert \'$tuple->[0]\'";
+	}
+}
+
+my @res = $box->Select([map $_->[0], @$tuples], { limit => 100 });
+foreach my $r (@res) {
+	ok sub { return $r != $tuples->[-1] && $r != $tuples->[-2] };
+}
+
diff --git a/scripts/run_test.sh b/scripts/run_test.sh
index b6d124f7e367ae77b8962234a61b7fa7a73f3072..ce6abef662c744e6f6d43c99f69b8f81009efa96 100755
--- a/scripts/run_test.sh
+++ b/scripts/run_test.sh
@@ -90,47 +90,57 @@ write_config() {
 	
 	namespace[0].enabled = 1
 	namespace[0].index[0].type = "HASH"
+	namespace[0].index[0].unique = 1
 	namespace[0].index[0].key_field[0].fieldno = 0
 	namespace[0].index[0].key_field[0].type = "NUM"
 	namespace[0].index[1].type = "HASH"
+	namespace[0].index[1].unique = 1
 	namespace[0].index[1].key_field[0].fieldno = 1
 	namespace[0].index[1].key_field[0].type = "STR"
 	
 	namespace[3].enabled = 1
 	namespace[3].index[0].type = "HASH"
+	namespace[3].index[0].unique = 1
 	namespace[3].index[0].key_field[0].fieldno = 0
 	namespace[3].index[0].key_field[0].type = "NUM"
 	
 	namespace[5].enabled = 1
 	namespace[5].index[0].type = "HASH"
+	namespace[5].index[0].unique = 1
 	namespace[5].index[0].key_field[0].fieldno = 0
 	namespace[5].index[0].key_field[0].type = "NUM"
 	
 	namespace[11].enabled = 1
 	namespace[11].index[0].type = "HASH"
+	namespace[11].index[0].unique = 1
 	namespace[11].index[0].key_field[0].fieldno = 0
 	namespace[11].index[0].key_field[0].type = "NUM"
 	
 	namespace[19].enabled = 1
 	namespace[19].index[0].type = "HASH"
+	namespace[19].index[0].unique = 1
 	namespace[19].index[0].key_field[0].fieldno = 0
 	namespace[19].index[0].key_field[0].type = "STR"
 	
 	namespace[22].enabled = 1
 	namespace[22].index[0].type = "HASH"
+	namespace[22].index[0].unique = 1
 	namespace[22].index[0].key_field[0].fieldno = 0
 	namespace[22].index[0].key_field[0].type = "NUM"
 	
 	namespace[23].enabled = 1
 	namespace[23].index[0].type = "HASH"
+	namespace[23].index[0].unique = 1
 	namespace[23].index[0].key_field[0].fieldno = 0
 	namespace[23].index[0].key_field[0].type = "NUM"
 	
 	namespace[24].enabled = 1
 	namespace[24].index[0].type = "HASH"
+	namespace[24].index[0].unique = 1
 	namespace[24].index[0].key_field[0].fieldno = 0
 	namespace[24].index[0].key_field[0].type = "NUM"
 	namespace[24].index[1].type = "HASH"
+	namespace[24].index[1].unique = 1
 	namespace[24].index[1].key_field[0].fieldno = 1
 	namespace[24].index[1].key_field[0].type = "STR"
 	
@@ -142,17 +152,78 @@ write_config() {
 
 	namespace[26].enabled = 1
 	namespace[26].index[0].type = "HASH"
+	namespace[26].index[0].unique = 1
 	namespace[26].index[0].key_field[0].fieldno = 0
 	namespace[26].index[0].key_field[0].type = "NUM"
 	namespace[26].index[1].type = "TREE"
+	namespace[26].index[1].unique = 0
 	namespace[26].index[1].key_field[0].fieldno = 1
 	namespace[26].index[1].key_field[0].type = "STR"
 	namespace[26].index[2].type = "TREE"
+	namespace[26].index[2].unique = 1
 	namespace[26].index[2].key_field[0].fieldno = 1
 	namespace[26].index[2].key_field[0].type = "STR"
 	namespace[26].index[2].key_field[1].fieldno = 2
 	namespace[26].index[2].key_field[1].type = "NUM"
 
+	namespace[27] = {
+		enabled = 1
+
+		# Email
+		index[0] = {
+			type = "HASH"
+			unique = 1
+
+			key_field[0] = {
+				type = "NUM"
+				fieldno = 0
+			}
+		}
+		index[1] = {
+			type = "TREE"
+			unique = 1
+
+			key_field[0] = {
+				type = "STR"
+				fieldno = 1
+			}
+		}
+		# FirstName
+		index[2] = {
+			type = "TREE"
+			unique = 0
+
+			key_field[0] = {
+				type = "STR"
+				fieldno = 2
+			}
+		}
+		# LastName
+		index[3] = {
+			type = "TREE"
+			unique = 0
+
+			key_field[0] = {
+				type = "STR"
+				fieldno = 3
+			}
+		}
+		# FullName
+		index[4] = {
+			type = "TREE"
+			unique = 1
+
+			key_field[0] = {
+				type = "STR"
+				fieldno = 2
+			}
+			key_field[1] = {
+				type = "STR"
+				fieldno = 3
+			}
+		}
+	}
+
 EOF
 }