Data Types
ekoDB supports 16 comprehensive data types with flexible type enforcement per collection and per field.
Type Enforcement
- Write-time validation: Types are checked when data is inserted or updated
- Optional at key-value level: Key-value operations can be schema-less
- Required at document level: Collections can enforce schemas
- Dynamic inference: Types are automatically detected if not specified
- Explicit specification: Define schemas via
/api/collections/{collection}endpoint
Response Formats
ekoDB supports two response formats:
Typed Responses (Default)
Includes type metadata for strong typing:
{
"name": {
"type": "String",
"value": "Alice"
},
"age": {
"type": "Integer",
"value": 30
}
}
Benefits:
- Type safety
- Explicit type information
- Better for strongly-typed languages
Non-Typed Responses
Traditional NoSQL format:
{
"name": "Alice",
"age": 30
}
Benefits:
- Simpler JSON
- Smaller payload size
- Familiar format
Configuration: Set via /api/config endpoint or ekoDB App
Basic Types
String
UTF-8 encoded text data for names, descriptions, and general content.
{
"name": "Alice",
"email": "alice@example.com",
"description": "Software engineer"
}
Use Cases: Names, emails, descriptions, URLs, JSON strings
Integer
64-bit signed integers for whole numbers.
Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
{
"age": 30,
"count": 1000,
"year": 2024
}
Use Cases: Counters, ages, quantities, IDs
Float
64-bit IEEE 754 floating-point numbers for decimal values.
{
"price": 29.99,
"temperature": 98.6,
"percentage": 0.85
}
Use Cases: Prices, measurements, percentages, scientific data
Floats have precision limitations. For financial calculations, use Decimal instead.
Boolean
Binary true/false values for logical operations.
{
"isActive": true,
"hasAccess": false,
"verified": true
}
Use Cases: Flags, toggles, status indicators
ekoDB infers a field's type from the raw JSON you send: true/false →
Boolean, a JSON string → String, a whole number → Integer, a fractional
number → Float, an array → Array, an object → Object. The types below in
Advanced Numeric, Temporal, and (for Set/Vector) Collection are
not inferred from a raw value — a raw RFC 3339 string is stored as a
String, a raw array as an Array, and so on. To store one of these, send the
typed wrapper { "type": "<TypeName>", "value": <value> }.
One exception, via schema coercion: if the collection's schema declares a field
as Number or Decimal, a raw numeric value is upgraded to that type.
There is no string→DateTime/UUID/Decimal or array→Set/Vector coercion.
Advanced Numeric Types
Number
Flexible numeric type that holds either an integer or a float. A raw number is
inferred as Integer or Float, so request Number explicitly with the
{ "type": "Number", "value": … } wrapper (or declare the field as Number in
the schema, which coerces a raw number to Number):
{
"metric": { "type": "Number", "value": 42 }, // Number holding an integer
"average": { "type": "Number", "value": 42.5 } // Number holding a float
}
Use Cases: When you don't know if a value will be an integer or float
Benefits:
- Automatic type detection
- Seamless conversion
- Flexible queries
Decimal
Arbitrary-precision decimal numbers that avoid floating-point rounding errors.
The wrapper's value is a string (to preserve precision); a raw string is
stored as String, so use the wrapper (or declare the field as Decimal in the
schema, which coerces a raw numeric value to Decimal):
{
"balance": { "type": "Decimal", "value": "1234.56" },
"price": { "type": "Decimal", "value": "0.10" },
"total": { "type": "Decimal", "value": "999999.99" }
}
Use Cases:
- Financial calculations (currency, accounting)
- Scientific computations requiring exact precision
- Any scenario where
0.1 + 0.2must equal exactly0.3
Why Decimal?
- No binary floating-point approximation
- Exact decimal representation
- Precision-preserving internal storage
Temporal Types
DateTime
RFC 3339 formatted date-time values with timezone support. A raw RFC 3339
string is stored as a String; to store a true DateTime (which enables
date math and range semantics), use the wrapper with an RFC 3339 string value:
{
"createdAt": { "type": "DateTime", "value": "2026-01-01T00:00:00Z" },
"updatedAt": { "type": "DateTime", "value": "2026-12-31T23:59:59+00:00" },
"scheduledFor": { "type": "DateTime", "value": "2025-06-15T14:30:00-05:00" }
}
Format: ISO 8601 / RFC 3339
Timezone: Always include timezone (Z for UTC or offset)
Use Cases: Timestamps, scheduling, time-series data
Duration
Time-span values. The Duration wrapper's value is an integer number of
milliseconds (a raw string like "30s" is stored as a String, not a
Duration):
{
"timeout": { "type": "Duration", "value": 30000 }, // 30 seconds
"interval": { "type": "Duration", "value": 300000 }, // 5 minutes
"ttl": { "type": "Duration", "value": 7200000 } // 2 hours
}
The shorthand forms "30s", "5m", "1h", "7d" are accepted by the
key-value store's ttl field, which has its own duration parser — they are
not the Duration field type, whose wrapper takes milliseconds.
Use Cases: TTL, timeouts, intervals, expiration
Collection Types
Array
Ordered lists of heterogeneous elements, preserving insertion order.
{
"tags": ["rust", "database", "nosql"],
"scores": [95, 87, 92, 88],
"mixed": ["text", 42, true, null]
}
Features:
- Maintains order
- Allows duplicates
- Can contain different types
- Supports nested arrays
Use Cases: Tags, lists, ordered data, multi-value fields
Set
Unordered collections of unique values with automatic deduplication. A raw
array is stored as an Array, so use the wrapper to get a Set:
{
"uniqueTags": { "type": "Set", "value": ["rust", "database", "nosql"] },
"permissions": { "type": "Set", "value": ["read", "write", "delete"] }
}
Features:
- Automatic deduplication
- No guaranteed order
- Fast membership testing
- Unique values only
Use Cases: Unique tags, permissions, categories
Vector
Fixed-dimension numeric arrays optimized for embeddings and vector similarity
search. A raw array is stored as an Array, so use the wrapper to get a
Vector:
{
"embedding": { "type": "Vector", "value": [0.1, 0.2, 0.3, 0.4] },
"features": { "type": "Vector", "value": [1.5, 2.3, 0.8, 4.1] }
}
Features:
- Optimized for similarity search
- High-performance indexing for fast similarity search
- Cosine, Euclidean, Dot Product metrics
- Fixed dimensions per field
Use Cases:
- AI/ML embeddings
- Semantic search
- Recommendation systems
- Image/text similarity
Object
Nested documents/maps with key-value pairs for complex structured data.
{
"address": {
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94102"
},
"metadata": {
"source": "api",
"version": "1.0"
}
}
Features:
- Nested structure
- Flexible schema
- Supports all types as values
- Can be deeply nested
Use Cases: Nested data, complex structures, JSON documents
Specialized Types
UUID
Universally unique identifiers (RFC 4122) for globally unique record
identification. A raw string is stored as a String, so use the wrapper to get
a UUID:
{
"id": { "type": "UUID", "value": "550e8400-e29b-41d4-a716-446655440000" },
"userId": { "type": "UUID", "value": "6ba7b810-9dad-11d1-80b4-00c04fd430c8" }
}
Format: 8-4-4-4-12 hexadecimal digits
Use Cases: Unique identifiers, correlation IDs, distributed systems
Binary
Binary data for images, files, and other binary content. A raw string is
stored as a String; use the wrapper with a base64-encoded string value to
get Binary:
{
"image": { "type": "Binary", "value": "iVBORw0KGgoAAAANSUhEUgAAAAUA..." },
"file": { "type": "Binary", "value": "SGVsbG8gV29ybGQh" }
}
Encoding: base64 string on write (the wrapper also accepts a [0-255] byte
array); reads return a byte array
Storage: Efficient binary storage
Use Cases: Images, files, encrypted data, binary blobs
Bytes
Raw byte arrays for unencoded binary data storage. A raw array is stored as an
Array, so use the wrapper with a [0-255] byte-value array to get Bytes:
{
"rawData": { "type": "Bytes", "value": [72, 101, 108, 108, 111] } // "Hello"
}
Format: Array of decimal byte values (0-255)
Use Cases: Raw binary data, protocol buffers, custom encodings
Null
Explicit null/empty values for optional fields.
{
"middleName": null,
"deletedAt": null,
"optionalField": null
}
Use Cases: Optional fields, missing data, explicit absence
Type Conversion
ekoDB automatically handles type conversions where safe:
Number Type Flexibility
// Number can match Integer or Float
{ "value": 42 } // Integer
{ "value": 42.5 } // Float
Automatic Coercion
- Integer to Float (always safe, within f64's exact-integer range)
- Integer to Decimal (lossless)
- Float to Decimal (within Decimal's range)
- Integer or Float to Number (automatic)
Schema Definition
Define schemas to enforce types when creating a collection:
POST /api/collections/users
Content-Type: application/json
Authorization: Bearer {ADMIN_TOKEN}
{
"fields": {
"name": { "type": "String", "required": true },
"age": { "type": "Number", "min": 0, "max": 150 },
"email": { "type": "String", "unique": true },
"balance": { "type": "Decimal" },
"tags": { "type": "Array" },
"metadata": { "type": "Object" }
}
}
Note: See Collections & Schemas for complete schema management documentation.
Best Practices
✅ Do
- Use
Decimalfor financial data - Use
DateTimewith timezones - Use
Vectorfor embeddings - Use
Setfor unique collections - Define schemas for production collections
❌ Don't
- Use
Floatfor money (useDecimal) - Store dates as strings (use
DateTime) - Use
Arraywhen you need uniqueness (useSet) - Mix types inconsistently
Next Steps
- Learn Schemas: Schema Validation
- Query Types: Basic Operations
- Advanced Types: White Paper - Type System
Questions? Contact support@ekodb.io