Native

A `Variant` column is encoded as:

- `UInt64(LE)` discriminators mode prefix (`0` = BASIC, `1` = COMPACT). Native format output typically uses BASIC (`0`); COMPACT mode may appear when reading data stored with `use_compact_variant_discriminators_serialization` enabled.
- N `UInt8` discriminators, one per row.
- Each variant type's data as a separate bulk column containing only the matching rows, in discriminant order.

For example, `Variant(String, UInt32)` with 5 rows `[0::UInt32, 'hello', NULL, 3::UInt32, 'hello']` (sorted: `String` = 0, `UInt32` = 1):

```
00 00 00 00 00 00 00 00    // discriminators mode = BASIC
01 00 ff 01 00              // UInt32, String, NULL, UInt32, String

// String (2 values, rows 1 and 4)
05 68 65 6c 6c 6f          // "hello"
05 68 65 6c 6c 6f          // "hello"

// UInt32 (2 values, rows 0 and 3)
00 00 00 00                 // 0
03 00 00 00                 // 3
```

#### Dynamic[​](#dynamic "Direct link to Dynamic")

Unlike [RowBinary](/docs/interfaces/formats/RowBinary#dynamic) where each value is self-describing (type prefix + value), the Native format serializes `Dynamic` as a structure prefix followed by a [Variant](#variant) column.

The structure prefix contains a `UInt64(LE)` serialization version, then the number of dynamic types (as VarUInt), then the type names as strings. In version V1 the type count is written twice for compatibility. The data that follows is a `Variant` column whose type list is the dynamic types plus an internal `SharedVariant` type, sorted alphabetically.

For example, `Dynamic` with 5 rows `[0::UInt32, 'hello', NULL, 3::UInt32, 'hello']`:

```
// Structure prefix (V1)
01 00 00 00 00 00 00 00    // version = V1
02                          // num types (V1 writes twice)
02                          // num types
06 53 74 72 69 6e 67       // "String"
06 55 49 6e 74 33 32       // "UInt32"

// Variant data: Variant(SharedVariant, String, UInt32)
// discriminants: SharedVariant=0, String=1, UInt32=2
00 00 00 00 00 00 00 00    // discriminators mode = BASIC
02 01 ff 02 01              // UInt32, String, NULL, UInt32, String
// SharedVariant: 0 values
05 68 65 6c 6c 6f          // String: "hello"
05 68 65 6c 6c 6f          // String: "hello"
00 00 00 00                 // UInt32: 0
03 00 00 00                 // UInt32: 3
```

#### JSON[​](#json "Direct link to JSON")

Unlike [RowBinary](/docs/interfaces/formats/RowBinary#json) where each row is self-describing with path names and values, the Native format serializes `JSON` in a columnar structure. The encoding is complex and version-dependent: it consists of a structure prefix with the serialization version, dynamic path names, and shared data layout, followed by typed paths (each as a bulk column), dynamic paths (each as a [Dynamic](#dynamic) column), and shared data for overflow paths.

For simpler interoperability, consider using the setting `output_format_native_write_json_as_string=1`, which serializes JSON columns as plain JSON text strings (one `String` per row).

- [Description](#description)- [Data types wire format](#data-types-wire-format)
    - [Block structure](#block-structure)- [Multiple blocks](#multiple-blocks)- [Simple data types](#simple-data-types)- [Complex data types](#complex-data-types)

Was this page helpful?