Synchro maps PostgreSQL column types to a logical type system, which client SDKs then map to their local storage (SQLite on mobile).
PostgreSQL Type Logical Type SQLite Type Notes uuidstringTEXTtext, varchar, charstringTEXTIncludes character varying(n), character(n) integer, smallintintINTEGERIncludes serial, smallserial bigintint64INTEGERIncludes bigserial real, double precisionfloatREALnumeric, decimalfloatREALIncludes numeric(p,s), decimal(p,s) booleanbooleanINTEGER0 / 1timestamp with time zonedatetimeTEXTISO 8601 format timestamp without time zonedatetimeTEXTISO 8601 format datedateTEXTYYYY-MM-DDtime without time zonetimeTEXTHH:MM:SStime with time zonetimeTEXTHH:MM:SS+offsetjson, jsonbjsonTEXTSerialized JSON string byteabytesBLOBintervalstringTEXTPostgreSQL interval string representation tsvectorstringTEXTFull-text search vector as string ltreestringTEXTLabel tree path as string
PostgreSQL Type Logical Type SQLite Type Notes text[], varchar[]jsonTEXTSerialized as JSON array integer[], bigint[]jsonTEXTSerialized as JSON array uuid[]jsonTEXTSerialized as JSON array Any type with [] suffix jsonTEXTAll arrays serialize to JSON
PostgreSQL Type Logical Type SQLite Type Notes User-defined enums stringTEXTStored as string value Domains (base type) (base type) Resolved to underlying type halfvec(n)stringTEXTpgvector half-precision vector
Enum and domain resolution
When Synchro encounters a column type not in the core mapping, it queries pg_type to check if the type is a user-defined enum (mapped to string) or a domain (resolved to its base type and re-mapped). If neither, the column is rejected as unsupported.
These PostgreSQL types are not supported for sync. Using them on a synced table will produce an error at schema load time.
Type Category Examples Reason Geometric point, line, polygon, circleNo mobile equivalent Network inet, cidr, macaddrNot applicable to mobile sync Composite User-defined composite types Complex nested structure Bit strings bit, bit varyingRarely used in application tables XML xmlUse json/jsonb instead Range int4range, tsrange, daterangeNo SQLite equivalent
Workaround for unsupported types
If you need a column with an unsupported type on a synced table, store it in a supported type and convert at the application layer. For example, store inet as text, or store int4range as two separate integer columns.
Composite primary keys are not supported. Each synced table must have a single-column primary key. UUID is recommended.
Primary keys are always synced and cannot be listed in ProtectedColumns.
numeric/decimal maps to float , which means values are stored as REAL in SQLite. Floating-point precision loss may occur for values exceeding 15-17 significant digits. If exact decimal precision is critical, consider storing values as text and parsing in the application layer.
Timestamp precision : SQLite stores timestamps as TEXT in ISO 8601 format. Sub-second precision depends on client SDK parsing.
Timezone handling : Both timestamp with time zone and timestamp without time zone map to the same datetime logical type. The server normalizes to UTC.
Stored as INTEGER (0/1) on the client. Client SDKs handle the conversion transparently.
Stored as TEXT on the client. No binary UUID optimization is applied.
Enum values are not enforced client-side. The client stores the string value and can write any string. The server validates enum membership on push, rejecting invalid values.
Generated columns (PostgreSQL 12+): Server-computed values may not round-trip correctly. The generated expression is not replicated to the client.
Partitioned tables : Not tested with logical replication or the schema introspection queries.
Not all PostgreSQL defaults can be replicated to SQLite. The schema endpoint classifies each default and provides a SQLite-compatible expression where possible.
Kind Meaning noneColumn has no default portableDefault can be applied on the client server_onlyDefault only applies on the server; omitted on client
Default Kind Example Portable? Client Behavior NULLDEFAULT NULLYes Applied locally Literal number DEFAULT 0, DEFAULT 3.14Yes Applied locally Literal string DEFAULT 'active'Yes Applied locally Boolean literal DEFAULT true, DEFAULT falseYes Mapped to 1/0 JSON literal DEFAULT '{}'::jsonbYes Cast stripped, literal preserved CURRENT_TIMESTAMPDEFAULT CURRENT_TIMESTAMPYes SQLite CURRENT_TIMESTAMP CURRENT_DATEDEFAULT CURRENT_DATEYes SQLite CURRENT_DATE CURRENT_TIMEDEFAULT CURRENT_TIMEYes SQLite CURRENT_TIME now()DEFAULT now()Yes Mapped to CURRENT_TIMESTAMP Function call DEFAULT gen_random_uuid()No Server-only, omitted locally Sequence DEFAULT nextval(...)No Server-only, omitted locally Expression DEFAULT (now() + interval '30 days')No Server-only, omitted locally
Non-portable defaults on NOT NULL columns
If a push-enabled table has a NOT NULL column with a server_only default and no client-side default, inserts from the client will fail. Either make the column nullable, add a portable default, or list it in ProtectedColumns so clients never write to it.
The /sync/schema endpoint returns default_kind and sqlite_default_sql for each column:
"db_type" : " timestamp with time zone " ,
"logical_type" : " datetime " ,
"default_kind" : " portable " ,
"sqlite_default_sql" : " CURRENT_TIMESTAMP " ,
Constraint Server Client Notes PRIMARY KEYEnforced Enforced Single-column only NOT NULLEnforced Replicated Applied to client schema UNIQUEEnforced Single-column only Multi-column unique not replicated FOREIGN KEYEnforced Not enforced Client is a cache; FK integrity maintained by server CHECKEnforced Not enforced Server validates on push DEFAULTEnforced Portable only See portability matrix above
Foreign keys on the client
Client SDKs do not create foreign key constraints. The client database is a local cache of server-authoritative data. Referential integrity is enforced by the server on push, and the sync protocol’s dependency ordering ensures parent records arrive before children during pull and snapshot.
Columns listed in ProtectedColumns on a TableConfig are excluded from client writes (push). The server ignores values for these columns in push payloads. Common uses:
Server-computed columns (created_at, updated_at)
Ownership columns (user_id) that the server sets from the authenticated identity
Derived or aggregated values
The system columns id, created_at, updated_at, and deleted_at are always protected implicitly, along with the configured owner column.