diff --git a/src/access_control.rs b/src/access_control.rs
index 14544805e593b0e45ee32da2a64759ea0b262202..eb1c9833a46fd2b7237716dd7fcf92d67a6670e2 100644
--- a/src/access_control.rs
+++ b/src/access_control.rs
@@ -36,6 +36,7 @@ use tarantool::{
         box_access_check_ddl, box_access_check_space, PrivType,
         SchemaObjectType as TntSchemaObjectType,
     },
+    error::BoxError,
     session::{self, UserId},
     space::{Space, SystemSpace},
     tuple::Encode,
@@ -312,11 +313,11 @@ fn detect_role_grant_cycles(
     }
 
     if visited.contains(&(granted_role.id as i64)) {
-        let err = tarantool::error::BoxError::new(
+        let err = BoxError::new(
             tarantool::error::TarantoolErrorCode::RoleLoop,
             format!(
                 "Granting role {} to role {} would create a loop",
-                granted_role.name, grantee_name
+                granted_role.name, grantee_name,
             ),
         );
         return Err(err.into());
diff --git a/src/bootstrap_entries.rs b/src/bootstrap_entries.rs
index 546200d01b5b3e48d0b45006fcc4ee77f82b1d85..bc9d2f6959a201326a21686db31194bf22c085ac 100644
--- a/src/bootstrap_entries.rs
+++ b/src/bootstrap_entries.rs
@@ -1,6 +1,8 @@
 use ::raft::prelude as raft;
 use protobuf::Message;
 
+use ::tarantool::msgpack;
+
 use crate::config::PicodataConfig;
 use crate::instance::Instance;
 use crate::replicaset::Replicaset;
@@ -270,8 +272,12 @@ pub(super) fn prepare(
     let mut ops = vec![];
     for (table_def, index_defs) in schema::system_table_definitions() {
         ops.push(
-            op::Dml::insert(ClusterwideTable::Table, &table_def, ADMIN_ID)
-                .expect("serialization cannot fail"),
+            op::Dml::insert_raw(
+                ClusterwideTable::Table,
+                msgpack::encode(&table_def),
+                ADMIN_ID,
+            )
+            .expect("serialization cannot fail"),
         );
         for index_def in index_defs {
             ops.push(
diff --git a/src/rpc/ddl_apply.rs b/src/rpc/ddl_apply.rs
index a1334ca8f96ecccd486140df47a6418709388ab6..043e105e626c4bc2e13d86d6a099563ec645c3bd 100644
--- a/src/rpc/ddl_apply.rs
+++ b/src/rpc/ddl_apply.rs
@@ -10,7 +10,7 @@ use crate::traft::error::Error as TraftError;
 use crate::traft::node;
 use crate::traft::{RaftIndex, RaftTerm};
 use std::time::Duration;
-use tarantool::error::TarantoolErrorCode;
+use tarantool::error::{BoxError, TarantoolErrorCode};
 use tarantool::transaction::{transaction, TransactionError};
 
 crate::define_rpc_request! {
@@ -41,7 +41,7 @@ crate::define_rpc_request! {
         }
 
         if crate::tarantool::eval("return box.info.ro")? {
-            let e = tarantool::error::BoxError::new(
+            let e = BoxError::new(
                 TarantoolErrorCode::Readonly,
                 "cannot apply schema change on a read only instance"
             );
diff --git a/src/schema.rs b/src/schema.rs
index 192d869edf5b82e663b2ee4ee616d77a11cc09cf..f97f19fd3ff3a2a5aec4e7ac692afd462b8f4395 100644
--- a/src/schema.rs
+++ b/src/schema.rs
@@ -14,6 +14,7 @@ use tarantool::auth::AuthMethod;
 use tarantool::error::TarantoolError;
 use tarantool::error::TarantoolErrorCode;
 use tarantool::fiber;
+use tarantool::msgpack;
 use tarantool::session::{with_su, UserId};
 use tarantool::set_error;
 use tarantool::space::{FieldType, SpaceCreateOptions, SpaceEngineType};
@@ -59,7 +60,7 @@ pub const INITIAL_SCHEMA_VERSION: u64 = 0;
 /// Database table definition.
 ///
 /// Describes a user-defined table.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Clone, Debug, msgpack::Encode, msgpack::Decode, PartialEq, Eq)]
 pub struct TableDef {
     pub id: SpaceId,
     pub name: String,
@@ -71,8 +72,6 @@ pub struct TableDef {
     pub owner: UserId,
 }
 
-impl Encode for TableDef {}
-
 impl TableDef {
     /// Index (0-based) of field "operable" in the _pico_table table format.
     pub const FIELD_OPERABLE: usize = 5;
@@ -84,7 +83,7 @@ impl TableDef {
         vec![
             Field::from(("id", FieldType::Unsigned)),
             Field::from(("name", FieldType::String)),
-            Field::from(("distribution", FieldType::Array)),
+            Field::from(("distribution", FieldType::Map)),
             Field::from(("format", FieldType::Array)),
             Field::from(("schema_version", FieldType::Unsigned)),
             Field::from(("operable", FieldType::Boolean)),
@@ -100,7 +99,11 @@ impl TableDef {
             id: 10569,
             name: "stuff".into(),
             distribution: Distribution::Global,
-            format: vec![],
+            format: vec![tarantool::space::Field {
+                name: "field_1".into(),
+                field_type: tarantool::space::FieldType::Unsigned,
+                is_nullable: false,
+            }],
             schema_version: 420,
             operable: true,
             engine: SpaceEngineType::Blackhole,
@@ -177,7 +180,9 @@ pub fn fields_to_format(
 ////////////////////////////////////////////////////////////////////////////////
 
 /// Defines how to distribute tuples in a table across replicasets.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, LuaRead)]
+#[derive(
+    Clone, Debug, Serialize, Deserialize, PartialEq, Eq, LuaRead, msgpack::Encode, msgpack::Decode,
+)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "kind")]
 pub enum Distribution {
@@ -2478,8 +2483,10 @@ mod test {
     #[test]
     #[rustfmt::skip]
     fn space_def_matches_format() {
+        use ::tarantool::msgpack;
+        
         let i = TableDef::for_tests();
-        let tuple_data = i.to_tuple_buffer().unwrap();
+        let tuple_data = msgpack::encode(&i);
         let format = TableDef::format();
         crate::util::check_tuple_matches_format(tuple_data.as_ref(), &format, "TableDef::format");
 
diff --git a/src/sql/router.rs b/src/sql/router.rs
index bf1817fdf0b88b26b61a3bce5712f3a2a2f33398..f85ec2b5976e267cccf82a4eac5cd4a317cd7162 100644
--- a/src/sql/router.rs
+++ b/src/sql/router.rs
@@ -42,9 +42,11 @@ use std::borrow::Cow;
 
 use crate::sql::storage::StorageRuntime;
 use crate::traft::node;
-use tarantool::space::Space;
-use tarantool::tuple::{KeyDef, Tuple};
-use tarantool::util::Value as TarantoolValue;
+
+use ::tarantool::msgpack;
+use ::tarantool::space::Space;
+use ::tarantool::tuple::{KeyDef, Tuple};
+use ::tarantool::util::Value as TarantoolValue;
 
 pub type VersionMap = HashMap<SmolStr, u64>;
 
@@ -462,14 +464,14 @@ impl RouterMetadata {
         })?;
         let tuple =
             tuple.ok_or_else(|| SbroadError::NotFound(Entity::ShardingKey, name.to_smolstr()))?;
-        let space_def: TableDef = tuple.decode().map_err(|e| {
+        let table_def: TableDef = msgpack::decode(&tuple.to_vec()).map_err(|e| {
             SbroadError::FailedTo(
                 Action::Deserialize,
                 Some(Entity::SpaceMetadata),
                 format_smolstr!("serde error: {e}"),
             )
         })?;
-        let shard_cols: Vec<SmolStr> = match &space_def.distribution {
+        let shard_cols: Vec<SmolStr> = match &table_def.distribution {
             Distribution::Global => {
                 vec![]
             }
diff --git a/src/storage.rs b/src/storage.rs
index 6b186fa9a59a6240ccbdde3055e34811f449ad63..06e2cbf351405449e28e694966e15b0efbd0d4fe 100644
--- a/src/storage.rs
+++ b/src/storage.rs
@@ -1,6 +1,6 @@
 use tarantool::auth::AuthDef;
 use tarantool::decimal::Decimal;
-use tarantool::error::{Error as TntError, TarantoolErrorCode as TntErrorCode};
+use tarantool::error::{BoxError, Error as TntError, TarantoolErrorCode as TntErrorCode};
 use tarantool::fiber;
 use tarantool::index::{Index, IndexId, IndexIterator, IndexType, IteratorType};
 use tarantool::index::{IndexOptions, Part};
@@ -450,9 +450,13 @@ impl Clusterwide {
     }
 
     fn open_read_view(&self, entry_id: RaftEntryId) -> Result<SnapshotReadView> {
+        use ::tarantool::msgpack;
+
         let mut space_indexes = Vec::with_capacity(32);
 
-        for space_def in self.tables.iter()? {
+        for space_def in self.tables.index_iter()? {
+            let space_def: TableDef =
+                msgpack::decode(&space_def.to_vec()).map_err(TntError::from)?;
             if !matches!(space_def.distribution, Distribution::Global) {
                 continue;
             }
@@ -696,6 +700,8 @@ impl Clusterwide {
     #[allow(rustdoc::private_intra_doc_links)]
     /// [`NodeImpl::advance`]: crate::traft::node::NodeImpl::advance
     pub fn apply_snapshot_data(&self, data: &SnapshotData, is_master: bool) -> Result<()> {
+        use ::tarantool::msgpack;
+
         debug_assert!(unsafe { ::tarantool::ffi::tarantool::box_txn() });
 
         // These need to be saved before we truncate the corresponding spaces.
@@ -703,7 +709,8 @@ impl Clusterwide {
         let mut old_user_versions = HashMap::new();
         let mut old_priv_versions = HashMap::new();
 
-        for def in self.tables.iter()? {
+        for def in self.tables.index_iter()? {
+            let def: TableDef = msgpack::decode(&def.to_vec()).map_err(TntError::from)?;
             old_table_versions.insert(def.id, def.schema_version);
         }
         for def in self.users.iter()? {
@@ -767,7 +774,11 @@ impl Clusterwide {
         if is_master && v_local < v_snapshot {
             let t0 = std::time::Instant::now();
 
-            self.apply_schema_changes_on_master(self.tables.iter()?, &old_table_versions)?;
+            let tables = self.tables.index_iter()?.map(|tuple| {
+                msgpack::decode::<TableDef>(&tuple.to_vec())
+                    .expect("entry should be decoded correctly")
+            });
+            self.apply_schema_changes_on_master(tables, &old_table_versions)?;
             // TODO: secondary indexes
             self.apply_schema_changes_on_master(self.users.iter()?, &old_user_versions)?;
             self.apply_schema_changes_on_master(self.privileges.iter()?, &old_priv_versions)?;
@@ -2182,19 +2193,31 @@ impl Tables {
 
     #[inline]
     pub fn get(&self, id: SpaceId) -> tarantool::Result<Option<TableDef>> {
-        let tuple = self.space.get(&[id])?;
-        tuple.as_ref().map(Tuple::decode).transpose()
+        use ::tarantool::msgpack;
+
+        let Some(tuple) = self.space.get(&[id])? else {
+            return Ok(None);
+        };
+        let buf = tuple.to_vec();
+        let table_def = msgpack::decode(&buf)?;
+        Ok(Some(table_def))
     }
 
     #[inline]
-    pub fn put(&self, space_def: &TableDef) -> tarantool::Result<()> {
-        self.space.replace(space_def)?;
+    pub fn put(&self, table_def: &TableDef) -> tarantool::Result<()> {
+        use ::tarantool::msgpack;
+
+        self.space
+            .replace(RawBytes::new(&msgpack::encode(table_def)))?;
         Ok(())
     }
 
     #[inline]
-    pub fn insert(&self, space_def: &TableDef) -> tarantool::Result<()> {
-        self.space.insert(space_def)?;
+    pub fn insert(&self, table_def: &TableDef) -> tarantool::Result<()> {
+        use ::tarantool::msgpack;
+
+        self.space
+            .insert(RawBytes::new(&msgpack::encode(table_def)))?;
         Ok(())
     }
 
@@ -2213,8 +2236,15 @@ impl Tables {
 
     #[inline]
     pub fn by_name(&self, name: &str) -> tarantool::Result<Option<TableDef>> {
+        use ::tarantool::msgpack;
+
         let tuple = self.index_name.get(&[name])?;
-        tuple.as_ref().map(Tuple::decode).transpose()
+        if let Some(tuple) = tuple {
+            let table_def = msgpack::decode(&tuple.to_vec())?;
+            Ok(Some(table_def))
+        } else {
+            Ok(None)
+        }
     }
 }
 
@@ -2652,7 +2682,7 @@ pub fn ddl_create_space_on_master(
 
     let res = (|| -> tarantool::Result<()> {
         if tt_pk_def.parts.is_empty() {
-            return Err(tarantool::error::BoxError::new(
+            return Err(BoxError::new(
                 tarantool::error::TarantoolErrorCode::ModifyIndex,
                 format!(
                     "can't create index '{}' in space '{}': parts list cannot be empty",
diff --git a/src/traft/node.rs b/src/traft/node.rs
index ea13759e34ae34f8bdaf66aec6667a4c62a55167..8d27c91e998e83d0321b900db64c3a8d3f32a38a 100644
--- a/src/traft/node.rs
+++ b/src/traft/node.rs
@@ -1672,7 +1672,7 @@ impl NodeImpl {
                     }
                 }
 
-                let space_def = TableDef {
+                let table_def = TableDef {
                     id,
                     name,
                     distribution,
@@ -1682,10 +1682,10 @@ impl NodeImpl {
                     engine,
                     owner,
                 };
-                let res = self.storage.tables.insert(&space_def);
+                let res = self.storage.tables.insert(&table_def);
                 if let Err(e) = res {
                     // Ignore the error for now, let governor deal with it.
-                    tlog!(Warning, "failed creating space '{}': {e}", space_def.name);
+                    tlog!(Warning, "failed creating table '{}': {e}", table_def.name);
                 }
             }
 
diff --git a/src/traft/op.rs b/src/traft/op.rs
index 840bfd4e4612f27e0b96ca5ac2c1a7b4601a092f..1d7a0c7806e350f3703f542a55972a803f6f7152 100644
--- a/src/traft/op.rs
+++ b/src/traft/op.rs
@@ -512,6 +512,20 @@ impl Dml {
         Ok(res)
     }
 
+    #[inline(always)]
+    pub fn insert_raw(
+        space: impl Into<SpaceId>,
+        tuple: Vec<u8>,
+        initiator: UserId,
+    ) -> tarantool::Result<Self> {
+        let res = Self::Insert {
+            table: space.into(),
+            tuple: TupleBuffer::try_from_vec(tuple)?,
+            initiator,
+        };
+        Ok(res)
+    }
+
     /// Serializes `tuple` and returns an [`Dml::Replace`] in case of success.
     #[inline(always)]
     pub fn replace(
diff --git a/test/int/test_basics.py b/test/int/test_basics.py
index adc16cbe3ba3dad5bb0178ddd14af0b1b70d50a7..2b84f06aa7122d990da8eaa05ef547d421e2510d 100644
--- a/test/int/test_basics.py
+++ b/test/int/test_basics.py
@@ -423,38 +423,38 @@ Insert({_pico_privilege}, ["execute","role",3,32,1,0]),
 Insert({_pico_user}, [2,"public",0,null,1,"role"]),
 Insert({_pico_user}, [31,"super",0,null,1,"role"]))|
 |  0  | 1  |BatchDml(
-Insert({_pico_table}, [{_pico_table},"_pico_table",["global"],[["id","unsigned",false],["name","string",false],["distribution","array",false],["format","array",false],["schema_version","unsigned",false],["operable","boolean",false],["engine","string",false],["owner","unsigned",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_table},"_pico_table",{{"Global":null}},[{{"field_type":"unsigned","is_nullable":false,"name":"id"}},{{"field_type":"string","is_nullable":false,"name":"name"}},{{"field_type":"map","is_nullable":false,"name":"distribution"}},{{"field_type":"array","is_nullable":false,"name":"format"}},{{"field_type":"unsigned","is_nullable":false,"name":"schema_version"}},{{"field_type":"boolean","is_nullable":false,"name":"operable"}},{{"field_type":"string","is_nullable":false,"name":"engine"}},{{"field_type":"unsigned","is_nullable":false,"name":"owner"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_table},0,"_pico_table_id","tree",[{{"unique":true}}],[["id",null,null,null,null]],true,0,1]),
 Insert({_pico_index}, [{_pico_table},1,"_pico_table_name","tree",[{{"unique":true}}],[["name",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_index},"_pico_index",["global"],[["table_id","unsigned",false],["id","unsigned",false],["name","string",false],["type","string",false],["opts","array",false],["parts","array",false],["operable","boolean",false],["schema_version","unsigned",false],["owner","unsigned",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_index},"_pico_index",{{"Global":null}},[{{"field_type":"unsigned","is_nullable":false,"name":"table_id"}},{{"field_type":"unsigned","is_nullable":false,"name":"id"}},{{"field_type":"string","is_nullable":false,"name":"name"}},{{"field_type":"string","is_nullable":false,"name":"type"}},{{"field_type":"array","is_nullable":false,"name":"opts"}},{{"field_type":"array","is_nullable":false,"name":"parts"}},{{"field_type":"boolean","is_nullable":false,"name":"operable"}},{{"field_type":"unsigned","is_nullable":false,"name":"schema_version"}},{{"field_type":"unsigned","is_nullable":false,"name":"owner"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_index},0,"_pico_index_id","tree",[{{"unique":true}}],[["table_id",null,null,null,null],["id",null,null,null,null]],true,0,1]),
 Insert({_pico_index}, [{_pico_index},1,"_pico_index_name","tree",[{{"unique":true}}],[["table_id",null,null,null,null],["name",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_peer_address},"_pico_peer_address",["global"],[["raft_id","unsigned",false],["address","string",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_peer_address},"_pico_peer_address",{{"Global":null}},[{{"field_type":"unsigned","is_nullable":false,"name":"raft_id"}},{{"field_type":"string","is_nullable":false,"name":"address"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_peer_address},0,"_pico_peer_address_raft_id","tree",[{{"unique":true}}],[["raft_id",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_instance},"_pico_instance",["global"],[["instance_id","string",false],["instance_uuid","string",false],["raft_id","unsigned",false],["replicaset_id","string",false],["replicaset_uuid","string",false],["current_grade","array",false],["target_grade","array",false],["failure_domain","map",false],["tier","string",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_instance},"_pico_instance",{{"Global":null}},[{{"field_type":"string","is_nullable":false,"name":"instance_id"}},{{"field_type":"string","is_nullable":false,"name":"instance_uuid"}},{{"field_type":"unsigned","is_nullable":false,"name":"raft_id"}},{{"field_type":"string","is_nullable":false,"name":"replicaset_id"}},{{"field_type":"string","is_nullable":false,"name":"replicaset_uuid"}},{{"field_type":"array","is_nullable":false,"name":"current_grade"}},{{"field_type":"array","is_nullable":false,"name":"target_grade"}},{{"field_type":"map","is_nullable":false,"name":"failure_domain"}},{{"field_type":"string","is_nullable":false,"name":"tier"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_instance},0,"_pico_instance_id","tree",[{{"unique":true}}],[["instance_id",null,null,null,null]],true,0,1]),
 Insert({_pico_index}, [{_pico_instance},1,"_pico_instance_raft_id","tree",[{{"unique":true}}],[["raft_id",null,null,null,null]],true,0,1]),
 Insert({_pico_index}, [{_pico_instance},2,"_pico_instance_replicaset_id","tree",[{{"unique":false}}],[["replicaset_id",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_property},"_pico_property",["global"],[["key","string",false],["value","any",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_property},"_pico_property",{{"Global":null}},[{{"field_type":"string","is_nullable":false,"name":"key"}},{{"field_type":"any","is_nullable":false,"name":"value"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_property},0,"_pico_property_key","tree",[{{"unique":true}}],[["key",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_replicaset},"_pico_replicaset",["global"],[["replicaset_id","string",false],["replicaset_uuid","string",false],["current_master_id","string",false],["target_master_id","string",false],["tier","string",false],["weight","number",false],["weight_origin","string",false],["state","string",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_replicaset},"_pico_replicaset",{{"Global":null}},[{{"field_type":"string","is_nullable":false,"name":"replicaset_id"}},{{"field_type":"string","is_nullable":false,"name":"replicaset_uuid"}},{{"field_type":"string","is_nullable":false,"name":"current_master_id"}},{{"field_type":"string","is_nullable":false,"name":"target_master_id"}},{{"field_type":"string","is_nullable":false,"name":"tier"}},{{"field_type":"number","is_nullable":false,"name":"weight"}},{{"field_type":"string","is_nullable":false,"name":"weight_origin"}},{{"field_type":"string","is_nullable":false,"name":"state"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_replicaset},0,"_pico_replicaset_id","tree",[{{"unique":true}}],[["replicaset_id",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_user},"_pico_user",["global"],[["id","unsigned",false],["name","string",false],["schema_version","unsigned",false],["auth","array",true],["owner","unsigned",false],["type","string",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_user},"_pico_user",{{"Global":null}},[{{"field_type":"unsigned","is_nullable":false,"name":"id"}},{{"field_type":"string","is_nullable":false,"name":"name"}},{{"field_type":"unsigned","is_nullable":false,"name":"schema_version"}},{{"field_type":"array","is_nullable":true,"name":"auth"}},{{"field_type":"unsigned","is_nullable":false,"name":"owner"}},{{"field_type":"string","is_nullable":false,"name":"type"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_user},0,"_pico_user_id","tree",[{{"unique":true}}],[["id",null,null,null,null]],true,0,1]),
 Insert({_pico_index}, [{_pico_user},1,"_pico_user_name","tree",[{{"unique":true}}],[["name",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_privilege},"_pico_privilege",["global"],[["privilege","string",false],["object_type","string",false],["object_id","integer",false],["grantee_id","unsigned",false],["grantor_id","unsigned",false],["schema_version","unsigned",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_privilege},"_pico_privilege",{{"Global":null}},[{{"field_type":"string","is_nullable":false,"name":"privilege"}},{{"field_type":"string","is_nullable":false,"name":"object_type"}},{{"field_type":"integer","is_nullable":false,"name":"object_id"}},{{"field_type":"unsigned","is_nullable":false,"name":"grantee_id"}},{{"field_type":"unsigned","is_nullable":false,"name":"grantor_id"}},{{"field_type":"unsigned","is_nullable":false,"name":"schema_version"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_privilege},0,"_pico_privilege_primary","tree",[{{"unique":true}}],[["grantee_id",null,null,null,null],["object_type",null,null,null,null],["object_id",null,null,null,null],["privilege",null,null,null,null]],true,0,1]),
 Insert({_pico_index}, [{_pico_privilege},1,"_pico_privilege_object","tree",[{{"unique":false}}],[["object_type",null,null,null,null],["object_id",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_tier},"_pico_tier",["global"],[["name","string",false],["replication_factor","unsigned",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_tier},"_pico_tier",{{"Global":null}},[{{"field_type":"string","is_nullable":false,"name":"name"}},{{"field_type":"unsigned","is_nullable":false,"name":"replication_factor"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_tier},0,"_pico_tier_name","tree",[{{"unique":true}}],[["name",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_routine},"_pico_routine",["global"],[["id","unsigned",false],["name","string",false],["kind","string",false],["params","array",false],["returns","array",false],["language","string",false],["body","string",false],["security","string",false],["operable","boolean",false],["schema_version","unsigned",false],["owner","unsigned",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_routine},"_pico_routine",{{"Global":null}},[{{"field_type":"unsigned","is_nullable":false,"name":"id"}},{{"field_type":"string","is_nullable":false,"name":"name"}},{{"field_type":"string","is_nullable":false,"name":"kind"}},{{"field_type":"array","is_nullable":false,"name":"params"}},{{"field_type":"array","is_nullable":false,"name":"returns"}},{{"field_type":"string","is_nullable":false,"name":"language"}},{{"field_type":"string","is_nullable":false,"name":"body"}},{{"field_type":"string","is_nullable":false,"name":"security"}},{{"field_type":"boolean","is_nullable":false,"name":"operable"}},{{"field_type":"unsigned","is_nullable":false,"name":"schema_version"}},{{"field_type":"unsigned","is_nullable":false,"name":"owner"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_routine},0,"_pico_routine_id","tree",[{{"unique":true}}],[["id",null,null,null,null]],true,0,1]),
 Insert({_pico_index}, [{_pico_routine},1,"_pico_routine_name","tree",[{{"unique":true}}],[["name",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_plugin},"_pico_plugin",["global"],[["name","string",false],["running","boolean",false],["services","array",false],["version","string",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_plugin},"_pico_plugin",{{"Global":null}},[{{"field_type":"string","is_nullable":false,"name":"name"}},{{"field_type":"boolean","is_nullable":false,"name":"running"}},{{"field_type":"array","is_nullable":false,"name":"services"}},{{"field_type":"string","is_nullable":false,"name":"version"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_plugin},0,"_pico_plugin_name","tree",[{{"unique":true}}],[["name",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_service},"_pico_service",["global"],[["plugin_name","string",false],["name","string",false],["version","string",false],["tiers","array",false],["configuration","any",false],["schema_version","unsigned",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_service},"_pico_service",{{"Global":null}},[{{"field_type":"string","is_nullable":false,"name":"plugin_name"}},{{"field_type":"string","is_nullable":false,"name":"name"}},{{"field_type":"string","is_nullable":false,"name":"version"}},{{"field_type":"array","is_nullable":false,"name":"tiers"}},{{"field_type":"any","is_nullable":false,"name":"configuration"}},{{"field_type":"unsigned","is_nullable":false,"name":"schema_version"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_service},0,"_pico_service_name","tree",[{{"unique":true}}],[["plugin_name",null,null,null,null],["name",null,null,null,null],["version",null,null,null,null]],true,0,1]),
-Insert({_pico_table}, [{_pico_service_route},"_pico_service_route",["global"],[["instance_id","string",false],["plugin_name","string",false],["service_name","string",false],["poison","boolean",false]],0,true,"memtx",1]),
+Insert({_pico_table}, [{_pico_service_route},"_pico_service_route",{{"Global":null}},[{{"field_type":"string","is_nullable":false,"name":"instance_id"}},{{"field_type":"string","is_nullable":false,"name":"plugin_name"}},{{"field_type":"string","is_nullable":false,"name":"service_name"}},{{"field_type":"boolean","is_nullable":false,"name":"poison"}}],0,true,"memtx",1]),
 Insert({_pico_index}, [{_pico_service_route},0,"_pico_service_routing_key","tree",[{{"unique":true}}],[["instance_id",null,null,null,null],["plugin_name",null,null,null,null],["service_name",null,null,null,null]],true,0,1])
 )|
 |  0  | 1  |AddNode(1)|
diff --git a/test/int/test_ddl.py b/test/int/test_ddl.py
index 3bb2563025a7ec626755f73fa05272c4a8facf74..abfecea40468763dfe2cadf87e03f5112ddca3f4 100644
--- a/test/int/test_ddl.py
+++ b/test/int/test_ddl.py
@@ -84,8 +84,8 @@ def test_ddl_lua_api(cluster: Cluster):
     pico_space_def = [
         space_id,
         "space 2",
-        ["global"],
-        [["id", "unsigned", False]],
+        {"Global": None},
+        [{"field_type": "unsigned", "is_nullable": False, "name": "id"}],
         2,
         True,
         "memtx",
@@ -107,8 +107,8 @@ def test_ddl_lua_api(cluster: Cluster):
     pico_space_def = [
         space_id,
         "space the third",
-        ["global"],
-        [["id", "unsigned", False]],
+        {"Global": None},
+        [{"field_type": "unsigned", "is_nullable": False, "name": "id"}],
         3,
         True,
         "memtx",
@@ -122,12 +122,11 @@ def test_ddl_lua_api(cluster: Cluster):
     pico_space_def = [
         space_id,
         "stuffy",
-        ["sharded_implicitly", ["foo"], "murmur3"],
+        {"ShardedImplicitly": [["foo"], "murmur3"]},
         [
-            ["id", "unsigned", False],
-            # Automatically generated by picodata
-            ["bucket_id", "unsigned", False],
-            ["foo", "integer", False],
+            {"field_type": "unsigned", "is_nullable": False, "name": "id"},
+            {"field_type": "unsigned", "is_nullable": False, "name": "bucket_id"},
+            {"field_type": "integer", "is_nullable": False, "name": "foo"},
         ],
         4,
         True,
@@ -284,8 +283,8 @@ def test_ddl_create_table_bulky(cluster: Cluster):
     pico_space_def = [
         space_id,
         "stuff",
-        ["global"],
-        [["id", "unsigned", False]],
+        {"Global": None},
+        [{"field_type": "unsigned", "is_nullable": False, "name": "id"}],
         2,
         True,
         "memtx",
@@ -396,13 +395,13 @@ def test_ddl_create_sharded_space(cluster: Cluster):
     pico_space_def = [
         space_id,
         "stuff",
-        ["sharded_implicitly", ["foo", "bar"], "murmur3"],
+        {"ShardedImplicitly": [["foo", "bar"], "murmur3"]},
         [
-            ["id", "unsigned", False],
+            {"field_type": "unsigned", "is_nullable": False, "name": "id"},
             # Automatically generated by picodata
-            ["bucket_id", "unsigned", False],
-            ["foo", "integer", False],
-            ["bar", "string", False],
+            {"field_type": "unsigned", "is_nullable": False, "name": "bucket_id"},
+            {"field_type": "integer", "is_nullable": False, "name": "foo"},
+            {"field_type": "string", "is_nullable": False, "name": "bar"},
         ],
         schema_version,
         True,