Introduction
With strict mode enabled, all fields are treated as a register by default. When enabled, every field in a document must match the collection definition exactly — including its CRDT type (e.g., map, register, counter). Disabling strict mode enables new functionality: when set tofalse
,
collection definitions are no longer required. SELECT queries
will return and display all fields by default. This matches the behavior of the
legacy query language. - objects in INSERT and UPDATE statements are treated as
maps. When a field has multiple possible types, the most recently updated type
is chosen.
Important for Cross-Peer SynchronizationWhen peers have different
DQL_STRICT_MODE
settings:- Data WILL sync between peers, but behavior changes
- When strict mode is
true
(4.10 and below), nested objects default to REGISTER type - For consistent behavior, either use matching strict mode settings across all peers OR explicitly define MAP types in your collection definitions in 4.10 and below.
Compatibility
Feature | SDK <4.10: DQL_STRICT_MODE=true | SDK 4.11+: DQL_STRICT_MODE=false |
---|---|---|
Nested MAPs | ❌ Requires explicit definitions | ✅ Supported (automatic inference) |
Collection Definitions | ❌ Required | ✅ Optional |
Legacy Compatibility | ❌ Not supported | ✅ Supported |
Default object type | REGISTER (whole object replacement) | MAP (field-level merging) |
Nested field updates without definitions | ⚠️ Replaces entire object | ✅ Merges individual fields |
Strict mode is enabled (set to
true
) in v4, but will be set to false
in v5.HTTP Usage
Critical for Cross-Peer Sync with HTTP APIWhen using HTTP API with SDK peers:
- If SDK peers have
DQL_STRICT_MODE=false
, you MUST use the/store/v5/execute
endpoint - The v4 endpoint (
/store/v4/execute
) does not supportDQL_STRICT_MODE=false
- Mismatched API versions can cause nested field sync issues similar to mismatched strict mode settings
/store/v5/execute
endpoint.
This endpoint allows you to execute DQL statements without needing to define
collection types and properly handles DQL_STRICT_MODE=false
behavior.
Endpoint Compatibility:
Endpoint | Supports strict_mode=false | Use When |
---|---|---|
/store/v4/execute | ❌ No | All SDK peers have strict_mode=true |
/store/v5/execute | ✅ Yes | Any peers have strict_mode=false |
/store/v5/execute
and changes will sync to v4 clients without issues.
Example HTTP Request:
SDK Usage
First, disable strict mode before callingstartSync
or creating your DQL subscriptions, observers, or execute
statements.
Subscriptions
Subscriptions behave the same regardless of whetherDQL_STRICT_MODE
is enabled or disabled.
Example
WithDQL_STRICT_MODE=false
, objects are treated as maps. In the following
examples, items
is a map: each key points to some object. This structure is
common in NoSQL/document-style databases.
DQL_STRICT_MODE=false
,, Ditto infers the CRDT type based on the
document’s shape. No collection definition is required.
- When you define an object like
items: {"shake": ..., "fries": ...}
, Ditto treats that as a MAP when strict mode is disabled. - Whether you use Query Builder or DQL, this structure is preserved and behaves the same on both insert and read.
- This is useful to know if you’re working with dynamic key-value structures inside documents.
Updating Nested Maps
In 4.11 and above, useUPDATE
statement to set nested MAPs.
Using UPDATE
Updating Nested Maps with Dynamic Keys
UseINSERT
and ON ID CONFLICT DO UPDATE
to update nested maps with dynamic
UUIDs. This is the same behavior as using upsert
in the legacy query builder.
Deleting Nested Values
In 4.11 and above withDQL_STRICT_MODE=false
, use the UNSET
statement.
Register Maps
AREGISTER
is a data type in Ditto that stores a single scalar value and
uses last-write-wins merge strategy for handling conflicts.
With DQL_STRICT_MODE=false
, if you want a REGISTER JSON object data type in DQL, it must be
specified explicitly.
Key characteristics of REGISTER:
- Stores primitive types (string, boolean) or JSON objects
- Last-write-wins conflict resolution ensures consistent values across peers
How it works
WhenDQL_STRICT_MODE=false
, Ditto is more flexible and will infer the
CRDT type based on the document’s shape, meaning that collection definitions
are no longer required:
- Objects → treated as CRDT maps
- Scalars and arrays → treated as Registers
- Counters and attachments → inferred from operations
true
, Ditto infers the CRDT type based on the
document’s shape. By default, objects treated as registers, which means that
every field’s type must be specified in the collection definition.
In this case, the items field is a map, so it must be defined as such in the
collection definition.
Last Write Wins
WithDQL_STRICT_MODE=false
, if there is no collection definition provided,
objects will be implicitly updating the MAP after a dot update operation, even
if a register exists on disk.
This is called “last write wins” behavior, and it means that the last
operation to write to a field will overwrite any previous values, regardless of
the type of the field.
Cross-Peer Synchronization
Mixing Peers with Different Settings
You can mix peers with different strict mode settings, but understanding the behavior is crucial for proper data synchronization:Matched Settings (Recommended)
When all peers use the sameDQL_STRICT_MODE
setting, behavior is predictable:
- With
false
: Objects are treated as MAPs by default, nested updates work as expected - With
true
: Collection definitions are required, types must be explicitly defined
Mismatched Settings (Requires Careful Handling)
When peers have differentDQL_STRICT_MODE
settings:
- Data DOES sync between peers regardless of settings differences
- Default type behavior changes:
- Peer with
DQL_STRICT_MODE=true
treats undefined objects as REGISTERs - Peer with
DQL_STRICT_MODE=false
treats objects as MAPs
- Peer with
- This affects nested field updates significantly
- Option 1: Match strict mode settings across all peers (simplest)
- Option 2: Explicitly define MAP types in collection definitions
Version Compatibility
Scenario | v4.10 and earlier | v4.11+ |
---|---|---|
All peers same setting | Requires collection definitions | Works with or without definitions |
Mixed settings, no definitions | Nested updates may fail | Objects default to REGISTER on strict=true peers |
Mixed settings, with MAP definitions | Works correctly | Works correctly |
Troubleshooting Nested Field Sync Issues
Common Symptom: “Nested fields are not syncing”
This is often caused by mismatched strict mode settings between peers without explicit MAP definitions.Diagnostic Steps
- Check strict mode on all peers:
- Verify your update query:
- Check how the data appears on each peer:
Real-World Example Fix
Problem: Updating nested fieldse:strict_mode=true
while the updating peer has strict_mode=false
. Without a MAP definition, metadata
is treated as a REGISTER.
Solutions: