diff --git a/changelogs/unreleased/gh-8649-always-set-exclude_null-to-true-or-false.md b/changelogs/unreleased/gh-8649-always-set-exclude_null-to-true-or-false.md
new file mode 100644
index 0000000000000000000000000000000000000000..c056cfd8e56d401ae1cd41767d70fe7d07e182fe
--- /dev/null
+++ b/changelogs/unreleased/gh-8649-always-set-exclude_null-to-true-or-false.md
@@ -0,0 +1,4 @@
+## bugfix/core
+
+* Now `index_object.parts.exclude_null` always contains `false` rather than
+  `null` when it is actually `false` (gh-8649).
diff --git a/src/box/lua/key_def.c b/src/box/lua/key_def.c
index d5dfa83695fd1348798201926a850eb34ceb5abc..2ea239f4a6d3eb6ef7db6c511c085abced9353f4 100644
--- a/src/box/lua/key_def.c
+++ b/src/box/lua/key_def.c
@@ -93,10 +93,8 @@ luaT_push_key_def_parts(struct lua_State *L, const struct key_def *key_def)
 		lua_pushboolean(L, key_part_is_nullable(part));
 		lua_setfield(L, -2, "is_nullable");
 
-		if (part->exclude_null) {
-			lua_pushboolean(L, true);
-			lua_setfield(L, -2, "exclude_null");
-		}
+		lua_pushboolean(L, part->exclude_null);
+		lua_setfield(L, -2, "exclude_null");
 
 		if (part->coll_id != COLL_NONE) {
 			const char *name;
diff --git a/test/box-luatest/gh_7356_index_parts_methods_test.lua b/test/box-luatest/gh_7356_index_parts_methods_test.lua
index 1ea3c26c7a8ca735cb415ced56bfb34b939a7229..7bee5ca5c95b1d3b7a75e25939f97cb98167f11e 100644
--- a/test/box-luatest/gh_7356_index_parts_methods_test.lua
+++ b/test/box-luatest/gh_7356_index_parts_methods_test.lua
@@ -129,9 +129,12 @@ g.test_merge = function(cg)
                                                 {type = 'scalar', field = 2}}})
         local j = s:create_index('j', {parts = {{type = 'unsigned', field = 1},
                                                 {type = 'string', field = 3}}})
-        local exp = {{fieldno = 3, type = 'string', is_nullable = false},
-                     {fieldno = 2, type = 'scalar', is_nullable = false},
-                     {fieldno = 1, type = 'unsigned', is_nullable = false}}
+        local exp = {{fieldno = 3, type = 'string', is_nullable = false,
+                      exclude_null = false},
+                     {fieldno = 2, type = 'scalar', is_nullable = false,
+                      exclude_null = false},
+                     {fieldno = 1, type = 'unsigned', is_nullable = false,
+                      exclude_null = false}}
         t.assert_equals(i.parts:merge(j.parts):totable(), exp)
 
         t.assert_error_msg_content_equals(
diff --git a/test/box-tap/key_def.test.lua b/test/box-tap/key_def.test.lua
index 1b89dea1960af98ca9e25d2ddaeabb1f5c644f3a..3a83aea9f6c6e9ad6a6ae11103db3c4f15208cf3 100755
--- a/test/box-tap/key_def.test.lua
+++ b/test/box-tap/key_def.test.lua
@@ -30,6 +30,9 @@ local function set_key_part_defaults(parts)
         if res[i].is_nullable == nil then
             res[i].is_nullable = false
         end
+        if res[i].exclude_null == nil then
+            res[i].exclude_null = false
+        end
     end
     return res
 end
@@ -519,14 +522,15 @@ test:test('merge()', function(test)
     local key_def_cb = key_def_c:merge(key_def_b)
     local exp_parts = key_def_c:totable()
     exp_parts[#exp_parts + 1] = {type = 'number', fieldno = 3,
-        is_nullable = false}
+        is_nullable = false, exclude_null = false}
     test:is_deeply(key_def_cb:totable(), exp_parts,
         'case 3: verify with :totable()')
     test:is_deeply(key_def_cb:extract_key(tuple_a):totable(),
         {1, 1, box.NULL, 22}, 'case 3: verify with :extract_key()')
 
     local parts_unsigned = {
-        {type = 'unsigned', fieldno = 1, is_nullable = false},
+        {type = 'unsigned', fieldno = 1, is_nullable = false,
+         exclude_null = false},
     }
     local key_def_unsigned = key_def_lib.new(parts_unsigned)
     local key_def_string = key_def_lib.new({
@@ -549,9 +553,12 @@ test:test('merge()', function(test)
 
     local key_def_array_map = key_def_array:merge(key_def_map)
     local exp_parts = {
-        {type = 'array', fieldno = 1, is_nullable = false},
-        {type = 'unsigned', fieldno = 2, is_nullable = false},
-        {type = 'map', fieldno = 3, is_nullable = true},
+        {type = 'array', fieldno = 1, is_nullable = false,
+         exclude_null = false},
+        {type = 'unsigned', fieldno = 2, is_nullable = false,
+         exclude_null = false},
+        {type = 'map', fieldno = 3, is_nullable = true,
+         exclude_null = false},
     }
     test:is_deeply(key_def_array_map:totable(), exp_parts,
         'composite case')
diff --git a/test/box/alter.result b/test/box/alter.result
index b2ac94d410583dcd47266dc9ac5b64467b550c8b..17549523fbfa6eb06421477928054b15809a3506 100644
--- a/test/box/alter.result
+++ b/test/box/alter.result
@@ -705,9 +705,11 @@ s.index.pk
 - unique: true
   parts:
   - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 1
   - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 2
   hint: true
@@ -739,6 +741,7 @@ s.index.pk
 - unique: true
   parts:
   - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 1
   hint: true
@@ -752,6 +755,7 @@ s.index.secondary
 - unique: true
   parts:
   - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 2
   hint: true
diff --git a/test/box/errinj.result b/test/box/errinj.result
index 78b893f46bb38b201090df8ddbf89b45a5afd42c..105b11dfe22b38ac75366bd1787b73af7a7d0203 100644
--- a/test/box/errinj.result
+++ b/test/box/errinj.result
@@ -1721,6 +1721,7 @@ rtreespace:create_index('pk', {if_not_exists = true})
 - unique: true
   parts:
   - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 1
   hint: true
@@ -1733,6 +1734,7 @@ rtreespace:create_index('target', {type='rtree', dimension = 3, parts={2, 'array
 ---
 - parts:
   - type: array
+    exclude_null: false
     is_nullable: false
     fieldno: 2
   dimension: 3
diff --git a/test/box/gh-5998-one-tx-for-ddl.result b/test/box/gh-5998-one-tx-for-ddl.result
index ed01fbc26e9e3a64036780acd98f8b61a4ccdd9b..5745b9164314720189c4294fb10909c48e432f41 100644
--- a/test/box/gh-5998-one-tx-for-ddl.result
+++ b/test/box/gh-5998-one-tx-for-ddl.result
@@ -40,6 +40,7 @@ s1:create_index('pk')
  | - unique: true
  |   parts:
  |   - type: unsigned
+ |     exclude_null: false
  |     is_nullable: false
  |     fieldno: 1
  |   hint: true
diff --git a/test/box/lua.result b/test/box/lua.result
index fda387fc783cac435bb6e1a634a33af31fc4a200..7422393143b9a431cab6ef930f8c836dd90b2646 100644
--- a/test/box/lua.result
+++ b/test/box/lua.result
@@ -714,9 +714,11 @@ tmp = space:create_index('primary', { type = 'tree', parts = {3, 'unsigned', 2,
 space.index['primary'].parts
 ---
 - - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 3
   - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 2
 ...
diff --git a/test/box/misc.result b/test/box/misc.result
index 68fc4622dc19a472298713103fc9751fa218b1fe..dc969b484aef446eaaf0ff0c30a66e359cdd2f6d 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -185,6 +185,7 @@ end;
 t;
 ---
 - - 'type : unsigned'
+  - 'exclude_null : false'
   - 'is_nullable : false'
   - 'fieldno : 1'
 ...
@@ -849,15 +850,17 @@ not not s:create_index('test3', {parts = {{3, 'string', collation = 'UnIcOdE'}}}
 s:create_index('test4', {parts = {{4, 'string'}}}).parts
 ---
 - - type: string
+    exclude_null: false
     is_nullable: false
     fieldno: 4
 ...
 s:create_index('test5', {parts = {{5, 'string', collation = 'Unicode'}}}).parts
 ---
-- - type: string
-    is_nullable: false
+- - fieldno: 5
+    type: string
+    exclude_null: false
     collation: unicode
-    fieldno: 5
+    is_nullable: false
 ...
 s:drop()
 ---
@@ -1047,10 +1050,11 @@ i = s:create_index('test2', {parts = {{2, 'string', is_nullable = true, collatio
 ...
 i.parts
 ---
-- - type: string
-    is_nullable: true
+- - fieldno: 2
+    type: string
+    exclude_null: false
     collation: unicode
-    fieldno: 2
+    is_nullable: true
 ...
 i = s:create_index('test4', {parts = {3, 'string', is_nullable = true}})
 ---
@@ -1058,6 +1062,7 @@ i = s:create_index('test4', {parts = {3, 'string', is_nullable = true}})
 i.parts
 ---
 - - type: string
+    exclude_null: false
     is_nullable: true
     fieldno: 3
 ...
@@ -1066,10 +1071,11 @@ i = s:create_index('test5', {parts = {3, 'string', collation = 'unicode'}})
 ...
 i.parts
 ---
-- - type: string
-    is_nullable: false
+- - fieldno: 3
+    type: string
+    exclude_null: false
     collation: unicode
-    fieldno: 3
+    is_nullable: false
 ...
 i = s:create_index('test6', {parts = {4, 'string'}})
 ---
@@ -1077,6 +1083,7 @@ i = s:create_index('test6', {parts = {4, 'string'}})
 i.parts
 ---
 - - type: string
+    exclude_null: false
     is_nullable: false
     fieldno: 4
 ...
diff --git a/test/box/rtree_misc.result b/test/box/rtree_misc.result
index f93a597bacb7cad074c86cf95c4e64bafb375a2c..007d354a41b96ef80259ea99a25209839ed6b904 100644
--- a/test/box/rtree_misc.result
+++ b/test/box/rtree_misc.result
@@ -543,6 +543,7 @@ i.dimension
 i.parts
 ---
 - - type: array
+    exclude_null: false
     is_nullable: false
     fieldno: 2
 ...
diff --git a/test/box/tx_man.result b/test/box/tx_man.result
index 53e8cff3fea85a3ccc13badeed1fdd3fca145262..8eea6fd2a7015b51580f112940548c91f8886a18 100644
--- a/test/box/tx_man.result
+++ b/test/box/tx_man.result
@@ -3880,6 +3880,7 @@ s:create_index('sk', {parts = {{2, 'unsigned'}}})
  | - unique: true
  |   parts:
  |   - type: unsigned
+ |     exclude_null: false
  |     is_nullable: false
  |     fieldno: 2
  |   hint: true
diff --git a/test/engine/ddl.result b/test/engine/ddl.result
index ddd01520aa84c1c986fdcf53b4139ff6a9eea8d4..586684b925d56a31e6236efae8e93175dcfa1634 100644
--- a/test/engine/ddl.result
+++ b/test/engine/ddl.result
@@ -311,6 +311,7 @@ pk = space:create_index('pk', {parts={{field = 1, type = 'unsigned'}}})
 pk.parts
 ---
 - - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 1
 ...
@@ -323,6 +324,7 @@ pk = space:create_index('pk', {parts={{1, 'unsigned'}}})
 pk.parts
 ---
 - - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 1
 ...
@@ -335,6 +337,7 @@ pk = space:create_index('pk', {parts={{1, type='unsigned'}}})
 pk.parts
 ---
 - - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 1
 ...
@@ -726,6 +729,7 @@ s:format()
 s.index.sk3.parts
 ---
 - - type: string
+    exclude_null: false
     is_nullable: false
     fieldno: 2
 ...
@@ -953,6 +957,7 @@ s:create_index('test', {parts = {{field = 'test'}}})
 s:create_index('test', {parts = {1}}).parts
 ---
 - - type: scalar
+    exclude_null: false
     is_nullable: false
     fieldno: 1
 ...
@@ -980,6 +985,7 @@ s:create_index('test', {parts = {{field = 'test'}}})
 s:create_index('test1', {parts = {'test1'}}).parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 1
 ...
@@ -991,45 +997,54 @@ s:create_index('test2', {parts = {'test2'}}).parts
 s:create_index('test3', {parts = {{'test1', 'integer'}}}).parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 1
 ...
 s:create_index('test4', {parts = {{'test2', 'integer'}}}).parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 2
 ...
 s:create_index('test5', {parts = {{'test2', 'integer'}}}).parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 2
 ...
 s:create_index('test6', {parts = {1, 3}}).parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 1
   - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 3
 ...
 s:create_index('test7', {parts = {'test1', 4}}).parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 1
   - type: scalar
+    exclude_null: false
     is_nullable: false
     fieldno: 4
 ...
 s:create_index('test8', {parts = {{1, 'integer'}, {'test4', 'scalar'}}}).parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 1
   - type: scalar
+    exclude_null: false
     is_nullable: false
     fieldno: 4
 ...
@@ -1668,6 +1683,7 @@ i = s:create_index('primary', { parts = {'field1'} })
 i.parts
 ---
 - - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 1
 ...
@@ -1742,6 +1758,7 @@ i = s:create_index('secondary', { parts = {{2, 'string', is_nullable = true}} })
 i.parts
 ---
 - - type: string
+    exclude_null: false
     is_nullable: true
     fieldno: 2
 ...
diff --git a/test/engine/null.result b/test/engine/null.result
index 31abb9767f9a518381d2788e7daf7856bd8176bf..d803612c4fbda910fd15ccc1c6e2559a25dd43ec 100644
--- a/test/engine/null.result
+++ b/test/engine/null.result
@@ -1959,6 +1959,7 @@ sk2 = s:create_index('sk2', {parts={{2, 'number', is_nullable=true, exclude_null
 sk2.parts
 ---
 - - type: number
+    exclude_null: false
     is_nullable: true
     fieldno: 2
 ...
@@ -2124,6 +2125,7 @@ sk1:alter({parts={{2, 'number', is_nullable=true, exclude_null=false}}})
 sk1.parts
 ---
 - - type: number
+    exclude_null: false
     is_nullable: true
     fieldno: 2
 ...
@@ -2455,6 +2457,7 @@ sk = s:create_index('sk', {parts = {2, is_nullable=true}})
 sk.parts
 ---
 - - type: scalar
+    exclude_null: false
     is_nullable: true
     fieldno: 2
 ...
@@ -2466,10 +2469,11 @@ sk = s:create_index('sk', {parts = {2, is_nullable=true, collation='unicode'}})
 ...
 sk.parts
 ---
-- - type: scalar
-    is_nullable: true
+- - fieldno: 2
+    type: scalar
+    exclude_null: false
     collation: unicode
-    fieldno: 2
+    is_nullable: true
 ...
 sk:drop()
 ---
@@ -2479,10 +2483,11 @@ sk = s:create_index('sk', {parts = {2, type='string', is_nullable=true, collatio
 ...
 sk.parts
 ---
-- - type: string
-    is_nullable: true
+- - fieldno: 2
+    type: string
+    exclude_null: false
     collation: unicode
-    fieldno: 2
+    is_nullable: true
 ...
 sk:drop()
 ---
@@ -2493,10 +2498,11 @@ sk = s:create_index('sk', {parts = {2, is_nullable=true, 3}})
 ...
 sk.parts
 ---
-- - type: string
-    is_nullable: true
+- - fieldno: 2
+    type: string
+    exclude_null: false
     collation: unicode
-    fieldno: 2
+    is_nullable: true
 ...
 sk:drop()
 ---
@@ -2507,9 +2513,11 @@ sk = s:create_index('sk', {parts = {2, 3}})
 sk.parts
 ---
 - - type: scalar
+    exclude_null: false
     is_nullable: false
     fieldno: 2
   - type: scalar
+    exclude_null: false
     is_nullable: false
     fieldno: 3
 ...
@@ -2522,12 +2530,15 @@ sk = s:create_index('sk', {parts = {2, 3, 4}})
 sk.parts
 ---
 - - type: scalar
+    exclude_null: false
     is_nullable: false
     fieldno: 2
   - type: scalar
+    exclude_null: false
     is_nullable: false
     fieldno: 3
   - type: scalar
+    exclude_null: false
     is_nullable: false
     fieldno: 4
 ...
@@ -2540,9 +2551,11 @@ sk = s:create_index('sk', {parts = {{2, 'int'}, {3, 'string'}}})
 sk.parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: false
     fieldno: 2
   - type: string
+    exclude_null: false
     is_nullable: false
     fieldno: 3
 ...
@@ -2555,12 +2568,14 @@ sk = s:create_index('sk', {parts = {{2, is_nullable=true}, {3, collation='unicod
 sk.parts
 ---
 - - type: scalar
+    exclude_null: false
     is_nullable: true
     fieldno: 2
-  - type: scalar
-    is_nullable: false
+  - fieldno: 3
+    type: scalar
+    exclude_null: false
     collation: unicode
-    fieldno: 3
+    is_nullable: false
 ...
 sk:drop()
 ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 2cfb8fe4a1fd87cf37590ddb6fe459e7c04b6beb..b83aedc9123b5e7e7fae95504642a0fdbc528d26 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -82,36 +82,44 @@ box.execute("CREATE INDEX i4 ON t1 (id, c, b, a, d);")
 box.space.T1.index.I1.parts
 ---
 - - type: number
+    exclude_null: false
     is_nullable: true
     fieldno: 2
 ...
 box.space.T1.index.I2.parts
 ---
 - - type: integer
+    exclude_null: false
     is_nullable: true
     fieldno: 3
 ...
 box.space.T1.index.I3.parts
 ---
 - - type: string
+    exclude_null: false
     is_nullable: true
     fieldno: 4
 ...
 box.space.T1.index.I4.parts
 ---
 - - type: string
+    exclude_null: false
     is_nullable: false
     fieldno: 1
   - type: string
+    exclude_null: false
     is_nullable: true
     fieldno: 4
   - type: integer
+    exclude_null: false
     is_nullable: true
     fieldno: 3
   - type: number
+    exclude_null: false
     is_nullable: true
     fieldno: 2
   - type: scalar
+    exclude_null: false
     is_nullable: true
     fieldno: 5
 ...
diff --git a/test/vinyl/ddl.result b/test/vinyl/ddl.result
index 8cacc06d1604302543f5d878377d7f23a7812c6b..9968215fb33d84e7c6cba96efb572e1a1eaebd42 100644
--- a/test/vinyl/ddl.result
+++ b/test/vinyl/ddl.result
@@ -571,6 +571,7 @@ box.space.test.index.pk
 - unique: true
   parts:
   - type: unsigned
+    exclude_null: false
     is_nullable: false
     fieldno: 1
   options: