Type System

Motivation

Feast uses an internal type system to provide guarantees on training and serving data. Feast supports primitive types, array types, set types, map types, JSON, and struct types for feature values. Null types are not supported, although the UNIX_TIMESTAMP type is nullable. The type system is controlled by Value.protoarrow-up-right in protobuf and by types.pyarrow-up-right in Python. Type conversion logic can be found in type_map.pyarrow-up-right.

Supported Types

Feast supports the following data types:

Primitive Types

Feast Type
Python Type
Description

Int32

int

32-bit signed integer

Int64

int

64-bit signed integer

Float32

float

32-bit floating point

Float64

float

64-bit floating point

String

str

String/text value

Bytes

bytes

Binary data

Bool

bool

Boolean value

UnixTimestamp

datetime

Unix timestamp (nullable)

Uuid

uuid.UUID

UUID (any version)

TimeUuid

uuid.UUID

Time-based UUID (version 1)

Decimal

decimal.Decimal

Arbitrary-precision decimal number

Domain-Specific Primitive Types

These types are semantic aliases over Bytes for domain-specific use cases (e.g., RAG pipelines, image processing). They are stored as bytes at the proto level.

Feast Type
Python Type
Description

PdfBytes

bytes

PDF document binary data (used in RAG / document processing pipelines)

ImageBytes

bytes

Image binary data (used in image processing / multimodal pipelines)

circle-exclamation

Array Types

All primitive types have corresponding array (list) types:

Feast Type
Python Type
Description

Array(Int32)

List[int]

List of 32-bit integers

Array(Int64)

List[int]

List of 64-bit integers

Array(Float32)

List[float]

List of 32-bit floats

Array(Float64)

List[float]

List of 64-bit floats

Array(String)

List[str]

List of strings

Array(Bytes)

List[bytes]

List of binary data

Array(Bool)

List[bool]

List of booleans

Array(UnixTimestamp)

List[datetime]

List of timestamps

Array(Uuid)

List[uuid.UUID]

List of UUIDs

Array(TimeUuid)

List[uuid.UUID]

List of time-based UUIDs

Array(Decimal)

List[decimal.Decimal]

List of arbitrary-precision decimals

Set Types

All primitive types (except Map and Json) have corresponding set types for storing unique values:

Feast Type
Python Type
Description

Set(Int32)

Set[int]

Set of unique 32-bit integers

Set(Int64)

Set[int]

Set of unique 64-bit integers

Set(Float32)

Set[float]

Set of unique 32-bit floats

Set(Float64)

Set[float]

Set of unique 64-bit floats

Set(String)

Set[str]

Set of unique strings

Set(Bytes)

Set[bytes]

Set of unique binary data

Set(Bool)

Set[bool]

Set of unique booleans

Set(UnixTimestamp)

Set[datetime]

Set of unique timestamps

Set(Uuid)

Set[uuid.UUID]

Set of unique UUIDs

Set(TimeUuid)

Set[uuid.UUID]

Set of unique time-based UUIDs

Set(Decimal)

Set[decimal.Decimal]

Set of unique arbitrary-precision decimals

Note: Set types automatically remove duplicate values. When converting from lists or other iterables to sets, duplicates are eliminated.

circle-exclamation

Nested Collection Types

Feast supports arbitrarily nested collections using a recursive VALUE_LIST / VALUE_SET design. The outer container determines the proto enum (VALUE_LIST for Array(…), VALUE_SET for Set(…)), while the full inner type structure is persisted via a mandatory feast:nested_inner_type Field tag.

Feast Type
Python Type
ValueType
Description

Array(Array(T))

List[List[T]]

VALUE_LIST

List of lists

Array(Set(T))

List[List[T]]

VALUE_LIST

List of sets

Set(Array(T))

List[List[T]]

VALUE_SET

Set of lists

Set(Set(T))

List[List[T]]

VALUE_SET

Set of sets

Array(Array(Array(T)))

List[List[List[T]]]

VALUE_LIST

3-level nesting

Where T is any supported primitive type (Int32, Int64, Float32, Float64, String, Bytes, Bool, UnixTimestamp) or another nested collection type.

Notes:

  • Nesting depth is unlimited. Array(Array(Array(T))), Set(Array(Set(T))), etc. are all supported.

  • Inner type information is preserved via Field tags (feast:nested_inner_type) and restored during deserialization. This tag is mandatory for nested collection types.

  • Empty inner collections ([]) are stored as empty proto values and round-trip as None. For example, [[1, 2], [], [3]] becomes [[1, 2], None, [3]] after a write-read cycle.

Map Types

Map types allow storing dictionary-like data structures:

Feast Type
Python Type
Description

Map

Dict[str, Any]

Dictionary with string keys and values of any supported Feast type (including nested maps)

Array(Map)

List[Dict[str, Any]]

List of dictionaries

Note: Map keys must always be strings. Map values can be any supported Feast type, including primitives, arrays, or nested maps at the proto level. However, the PyArrow representation is map<string, string>, which means backends that rely on PyArrow schemas (e.g., during materialization) treat Map as string-to-string.

Backend support for Map:

Backend
Native Type
Notes

PostgreSQL

jsonb, jsonb[]

jsonbMap, jsonb[]Array(Map)

Snowflake

VARIANT, OBJECT

Inferred as Map

Redshift

SUPER

Inferred as Map

Spark

map<string,string>

map<>Map, array<map<>>Array(Map)

Athena

map

Inferred as Map

MSSQL

nvarchar(max)

Serialized as string

DynamoDB / Redis

Proto bytes

Full proto Map support

JSON Type

The Json type represents opaque JSON data. Unlike Map, which is schema-free key-value storage, Json is stored as a string at the proto level but backends use native JSON types where available.

Feast Type
Python Type
Description

Json

str (JSON-encoded)

JSON data stored as a string at the proto level

Array(Json)

List[str]

List of JSON strings

Backend support for Json:

Backend
Native Type

PostgreSQL

jsonb

Snowflake

JSON / VARIANT

Redshift

json

BigQuery

JSON

Spark

Not natively distinguished from String

MSSQL

nvarchar(max)

circle-info

When a backend's native type is ambiguous (e.g., PostgreSQL jsonb could be Map or Json), the schema-declared Feast type takes precedence. The backend-to-Feast mappings are only used during schema inference when no explicit type is provided.

Struct Type

The Struct type represents a schema-aware structured type with named, typed fields. Unlike Map (which is schema-free), a Struct declares its field names and their types, enabling schema validation.

Feast Type
Python Type
Description

Struct({"field": Type, ...})

Dict[str, Any]

Named fields with typed values

Array(Struct({"field": Type, ...}))

List[Dict[str, Any]]

List of structs

Example:

Backend support for Struct:

Backend
Native Type

BigQuery

STRUCT / RECORD

Spark

struct<...> / array<struct<...>>

PostgreSQL

jsonb (serialized)

Snowflake

VARIANT (serialized)

MSSQL

nvarchar(max) (serialized)

DynamoDB / Redis

Proto bytes

Complete Feature View Example

Below is a complete example showing how to define a feature view with all supported types:

Set Type Usage Examples

Sets store unique values and automatically remove duplicates:

UUID Type Usage Examples

UUID types store universally unique identifiers natively, with support for both random UUIDs and time-based UUIDs:

Decimal Type Usage Examples

The Decimal type stores arbitrary-precision decimal numbers using Python's decimal.Decimal. Values are stored as strings in the proto to preserve full precision — no floating-point rounding occurs.

circle-exclamation

Nested Collection Type Usage Examples

Limitation: Empty inner collections round-trip as None:

Map Type Usage Examples

Maps can store complex nested data structures:

JSON Type Usage Examples

Feast's Json type stores values as JSON strings at the proto level. You can pass either a pre-serialized JSON string or a Python dict/list — Feast will call json.dumps() automatically when the value is not already a string:

Struct Type Usage Examples

Type System in Practice

The sections below explain how Feast uses its type system in different contexts.

Feature inference

During feast apply, Feast runs schema inference on the data sources underlying feature views. For example, if the schema parameter is not specified for a feature view, Feast will examine the schema of the underlying data source to determine the event timestamp column, feature columns, and entity columns. Each of these columns must be associated with a Feast type, which requires conversion from the data source type system to the Feast type system.

  • The feature inference logic calls _infer_features_and_entities.

  • _infer_features_and_entities calls source_datatype_to_feast_value_type.

  • source_datatype_to_feast_value_type calls the appropriate method in type_map.py. For example, if a SnowflakeSource is being examined, snowflake_python_type_to_feast_value_type from type_map.py will be called.

circle-info

Types that cannot be inferred: Set, Json, Struct, Decimal, PdfBytes, and ImageBytes types are never inferred from backend schemas. If you use these types, you must declare them explicitly in your feature view schema.

Materialization

Feast serves feature values as Valuearrow-up-right proto objects, which have a type corresponding to Feast types. Thus Feast must materialize feature values into the online store as Value proto objects.

  • The local materialization engine first pulls the latest historical features and converts it to pyarrow.

  • Then it calls _convert_arrow_to_proto to convert the pyarrow table to proto format.

  • This calls python_values_to_proto_values in type_map.py to perform the type conversion.

Historical feature retrieval

The Feast type system is typically not necessary when retrieving historical features. A call to get_historical_features will return a RetrievalJob object, which allows the user to export the results to one of several possible locations: a Pandas dataframe, a pyarrow table, a data lake (e.g. S3 or GCS), or the offline store (e.g. a Snowflake table). In all of these cases, the type conversion is handled natively by the offline store. For example, a BigQuery query exposes a to_dataframe method that will automatically convert the result to a dataframe, without requiring any conversions within Feast.

Feature serving

As mentioned above in the section on materialization, Feast persists feature values into the online store as Value proto objects. A call to get_online_features will return an OnlineResponse object, which essentially wraps a bunch of Value protos with some metadata. The OnlineResponse object can then be converted into a Python dictionary, which calls feast_value_type_to_python_type from type_map.py, a utility that converts the Feast internal types to Python native types.

Last updated

Was this helpful?