Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ For how users sign in and how scopes work, see [Authentication](./authentication

## Pass and return data

Parameters and return values can be of type `bool`, `int`, `double`, `String`, `UuidValue`, `Duration`, `DateTime`, `ByteData`, `Uri`, `BigInt`, `dynamic`, [vector and geography types](./data-and-the-database/models/vector-and-geography-fields), or generated serializable objects ([data models](./data-and-the-database/models)). You can also use `List`, `Map`, `Record`, and `Set`, strictly typed with the types above. Null safety is supported, and return types follow the same rules as parameters. A `DateTime` is always converted to UTC when passed.
Parameters and return values can be of type `bool`, `int`, `double`, `String`, `UuidValue`, `Duration`, `DateTime`, `ByteData`, `Uri`, `BigInt`, [`dynamic`](./data-and-the-database/models/dynamic-fields), [vector and geography types](./data-and-the-database/models/vector-and-geography-fields), or generated serializable objects ([data models](./data-and-the-database/models)). You can also use `List`, `Map`, `Record`, and `Set`, strictly typed with the types above. Null safety is supported, and return types follow the same rules as parameters. A `DateTime` is always converted to UTC when passed.

Parameters are sent by name in the request between app and server, so renaming an endpoint method's parameters breaks older app builds. See [backward compatibility](./data-and-the-database/models/backward-compatibility) before changing a published API.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fields:
employees: List<Employee>
```

Supported types are [bool](https://api.dart.dev/dart-core/bool-class.html), [int](https://api.dart.dev/dart-core/int-class.html), [double](https://api.dart.dev/dart-core/double-class.html), [String](https://api.dart.dev/dart-core/String-class.html), [Duration](https://api.dart.dev/dart-core/Duration-class.html), [DateTime](https://api.dart.dev/dart-core/DateTime-class.html), [ByteData](https://api.dart.dev/dart-typed_data/ByteData-class.html), [UuidValue](https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html), [Uri](https://api.dart.dev/dart-core/Uri-class.html), [BigInt](https://api.dart.dev/dart-core/BigInt-class.html), [Vector](./models/vector-and-geography-fields#vector), [HalfVector](./models/vector-and-geography-fields#halfvector), [SparseVector](./models/vector-and-geography-fields#sparsevector), [Bit](./models/vector-and-geography-fields#bit), [GeographyPoint](./models/vector-and-geography-fields#geographypoint), [GeographyLineString](./models/vector-and-geography-fields#geographylinestring), [GeographyPolygon](./models/vector-and-geography-fields#geographypolygon), [GeographyGeometryCollection](./models/vector-and-geography-fields#geographygeometrycollection) and other serializable [classes](#class), [exceptions](#exception) and [enums](#enum). You can also use [List](https://api.dart.dev/dart-core/List-class.html)s, [Map](https://api.dart.dev/dart-core/Map-class.html)s and [Set](https://api.dart.dev/dart-core/Set-class.html)s of the supported types, just make sure to specify the types. All supported types can also be used inside [Record](https://api.dart.dev/dart-core/Record-class.html)s. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods.
Supported types are [bool](https://api.dart.dev/dart-core/bool-class.html), [int](https://api.dart.dev/dart-core/int-class.html), [double](https://api.dart.dev/dart-core/double-class.html), [String](https://api.dart.dev/dart-core/String-class.html), [Duration](https://api.dart.dev/dart-core/Duration-class.html), [DateTime](https://api.dart.dev/dart-core/DateTime-class.html), [ByteData](https://api.dart.dev/dart-typed_data/ByteData-class.html), [UuidValue](https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html), [Uri](https://api.dart.dev/dart-core/Uri-class.html), [BigInt](https://api.dart.dev/dart-core/BigInt-class.html), [dynamic](./models/dynamic-fields), [Vector](./models/vector-and-geography-fields#vector), [HalfVector](./models/vector-and-geography-fields#halfvector), [SparseVector](./models/vector-and-geography-fields#sparsevector), [Bit](./models/vector-and-geography-fields#bit), [GeographyPoint](./models/vector-and-geography-fields#geographypoint), [GeographyLineString](./models/vector-and-geography-fields#geographylinestring), [GeographyPolygon](./models/vector-and-geography-fields#geographypolygon), [GeographyGeometryCollection](./models/vector-and-geography-fields#geographygeometrycollection) and other serializable [classes](#class), [exceptions](#exception) and [enums](#enum). You can also use [List](https://api.dart.dev/dart-core/List-class.html)s, [Map](https://api.dart.dev/dart-core/Map-class.html)s and [Set](https://api.dart.dev/dart-core/Set-class.html)s of the supported types, just make sure to specify the types. All supported types can also be used inside [Record](https://api.dart.dev/dart-core/Record-class.html)s. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods.

### Required fields

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
description: Store values of varying types in Serverpod models using dynamic fields, with serialization and database support for JSON and JSONB columns.
---

# Dynamic fields

Use `dynamic` fields when a model property needs to hold different value types at runtime, for example, plugin configuration, user-defined form responses, or JSON payloads from external APIs. Serverpod serializes the value with its type information so it round-trips correctly between the client, server, and database.

## Define a dynamic field

Add `dynamic` as the field type in your model file:

```yaml
class: FormResponse
table: form_response
fields:
formId: int
### The submitted value may be a string, number, bool, list, or map.
value: dynamic
```
Run `serverpod generate` to update the generated Dart classes.

### Nullability

The `dynamic` type is already nullable, so it is written without a `?`. Writing `dynamic?` or `List<dynamic?>` is invalid Dart syntax and will be rejected by the code generation.

## Supported values

A `dynamic` field can hold any value that Serverpod can serialize, including:

- Primitives such as `bool`, `int`, `double`, and `String`.
- Other supported core types such as `DateTime`, `Duration`, and `UuidValue`.
- Generated serializable models from your project, modules, and shared packages.
- Collections (`List`, `Map`, and `Set`), including mixed-type contents.
- Nested combinations of these values.

Below is an example with several dynamic and collection fields:

```yaml
class: DynamicExample
table: dynamic_example
fields:
payload: dynamic
jsonbPayload: dynamic
payloadList: List<dynamic>
payloadMap: Map<String, dynamic>
payloadSet: Set<dynamic>
payloadMapWithDynamicKeys: Map<dynamic, dynamic>
```

In Dart, assign values directly:

```dart
var object = DynamicExample(
payload: 42,
jsonbPayload: 10.23,
payloadList: [1, 'b', SimpleData(num: 7)],
payloadMap: {'a': 1, 'b': 2, 'c': SimpleData(num: 3)},
payloadSet: {1, 2, 3, 'd'},
payloadMapWithDynamicKeys: {'a': 1, 2: SimpleData(num: 1)},
);
```

Values round-trip through `toJson` and `fromJson`, endpoint calls, and database operations. Serverpod includes runtime type metadata in the serialized value. Treat that representation as an implementation detail rather than constructing or editing it directly.

Dynamic fields also work across project, module, and shared-package model boundaries. A dynamic field on a module or shared model can contain a generated model from the consuming project. Run `serverpod generate` after adding or changing the involved models so each generated protocol has the required type registrations.

## Use dynamic values in endpoints

Endpoint parameters and return values can use `dynamic` directly:

```dart
class UtilityEndpoint extends Endpoint {
Future<dynamic> echo(Session session, dynamic value) async {
return value;
}
}
```

The generated client preserves the runtime type when it sends and receives supported values. Endpoints also support using `dynamic` on collections, maps and sets.

## Store dynamic fields in the database

When the model has a `table` keyword, `dynamic` fields are stored in a `json` column by default.

To store the value as `jsonb` instead, set `serializationDataType=jsonb` on the field. This format supports [GIN indexing](../database/indexing#gin-indexes):

```yaml
class: Product
table: product
fields:
name: String
metadata: dynamic, serializationDataType=jsonb
```

See [Storing serializable fields as JSONB](../database/tables#storing-serializable-fields-as-jsonb) for class-level and project-level settings.

After adding or changing `dynamic` fields on a table model, run `serverpod create-migration` and apply the migration.

## Copy models with dynamic fields

Generated `copyWith` methods distinguish between omitting a dynamic field and explicitly passing `null`. Omitting the argument preserves its current value:

```dart
var updated = object.copyWith(id: 2);
```

Passing `null` clears the field:

```dart
var cleared = object.copyWith(payload: null);
```

## Limits

- **No compile-time type checks.** Cast values in Dart when you know the expected type (`value as String`, `value is SimpleData`).
- **No database schema validation.** The database stores the serialized JSON; invalid shapes are only caught at runtime in Dart.
- **Prefer typed models when the schema is stable.** `dynamic` trades type safety for flexibility.

## Related

- [Working with models](../models): model file syntax and supported types.
- [Working with endpoints](../../endpoints-and-apis): endpoint parameters and return values.
- [Database tables](../database/tables): how model fields map to columns, including JSONB storage.
- [Custom serialization](./custom-serialization): registering custom serializable classes.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ All fields are persisted by default and have an implicit `persist` set on each f

## Data representation

Storing a field with a primitive / core dart type will be handled as its respective type. However, if you use a complex type, such as another model, a `List`, or a `Map`, these will be stored as a `json` column in the database by default.
Storing a field with a primitive / core dart type will be handled as its respective type. However, if you use a complex type, such as another model, a `List`, a `Map`, or a [dynamic](../models/dynamic-fields) value, these will be stored as a `json` column in the database by default.

```yaml
class: Company
Expand All @@ -81,7 +81,7 @@ For a complete guide on how to work with relations see the [relation section](re
By default, complex types are stored as `json` in the database. You can opt into `jsonb` storage instead using the `serializationDataType` keyword. JSONB is a binary format that supports efficient querying and [GIN indexing](indexing#gin-indexes) for PostgreSQL.

:::info
The `serializationDataType` keyword is only valid on serializable field types (models, Lists, Maps). Primitive types like `String` and `int` have their own native database column types and are not affected by this setting.
The `serializationDataType` keyword is only valid on serializable field types (models, Lists, Maps, and `dynamic`). Primitive types like `String` and `int` have their own native database column types and are not affected by this setting.
:::

You can set `serializationDataType` at three levels, each overriding the one above it:
Expand Down
1 change: 1 addition & 0 deletions docs/06-concepts/lookups/model-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ Every keyword available in a Serverpod model file, and whether it applies to a `
## Related

- [Working with models](../data-and-the-database/models): how each keyword works, with examples.
- [Dynamic fields](../data-and-the-database/models/dynamic-fields): store and transfer values whose type varies at runtime.
- [Database tables](../data-and-the-database/database/tables): the database-specific keywords (`table`, `relation`, `persist`, and indexing).
Loading