This page documents every DuckDB type as it crosses to R and back: what a value of the type becomes when read, which R value writes it again, and what to do where neither works. See duckdb_types_arrow for a description of the conversion via Arrow.
The routes
Reading.
dbGetQuery() converts each column by its type, and four dbConnect() arguments change the shape,
with defaults bigint = "numeric", array = "none", map = "data.frame" and geometry = "blob".
dbGetQueryArrow() hands out the engine's own Arrow export instead,
and what each type becomes there, and in the R readers that convert the stream, is documented in duckdb_types_arrow.
A cast to VARCHAR in the query reads any type as text.
Writing.
dbWriteTable() and duckdb_register() take a column's type from its R class,
and field.types casts that column to the type it names, from any value that casts.
dbAppendTable() casts to the type of the existing column, and a parameter (params =) binds by its R class, cast by the query.
A character column holding a value's text form writes every scalar type through field.types, because DuckDB parses the text it prints.
Arrow, registered with duckdb_register_arrow(), writes the types no R class does.
Numbers
The numeric and boolean types:
BOOLEAN(BOOL,LOGICAL) reads aslogical, andlogicalwrites it.TINYINT,SMALLINT,UTINYINT,USMALLINTread asinteger, exactly.integerwritesINTEGER, andfield.typesnames the narrower type.INTEGER(INT4,INT,SIGNED) reads asinteger, exactly but for the minimum, andintegerwrites it.UINTEGERreads asnumeric, exactly;numericwritesDOUBLE, andfield.typesnamesUINTEGER.BIGINT(INT8,LONG) reads asnumeric, exact up to 2^53, and its rounding past that is a limitation. Withbigint = "integer64"it reads asbit64::integer64, exact but for the minimum. Aninteger64column or parameter writesBIGINTwhateverbigintsays.UBIGINTreads asnumeric, exact up to 2^53, and its rounding past that is a limitation. Withbigint = "integer64"it reads asinteger64, which holds the values below 2^63. Below 2^63, theinteger64it reads as writes it back throughfield.types, and its text writes any value.HUGEINT,UHUGEINTread asnumeric, andbigintdoes not change that; their rounding is a limitation. Their text is exact both ways.BIGNUM(VARINT) reads and writes through its text, and Arrow writes it (see duckdb_types_arrow).DECIMAL(width, scale)(NUMERIC) reads asnumericat every width; its rounding is a limitation. Its text is exact both ways, and Arrow writes it exactly.FLOAT(REAL) andDOUBLEread asnumeric, andnumericwritesDOUBLE.NaNreads and writes asNaN, never asNA, andNAisNULLin both directions.
Text and binary
The text, blob
and bitstring types, and UUID:
VARCHAR(CHAR,BPCHAR,TEXT,STRING) reads ascharacter, andcharacterwrites it; non-UTF-8 text is a limitation.BLOB(BYTEA,BINARY,VARBINARY) reads as a list of raw vectors. Ablob::blobor a list of raw vectors writes it.BIT(BITSTRING) reads and writes through its text.UUIDreads ascharacter, lowercase and hyphenated.characterwritesVARCHAR, andfield.typesmakes it aUUID.
Dates and times
The date, time, timestamp and interval types:
DATEreads asDate, and aDatewrites it, stored as double or as integer.TIMEreads asdifftimein seconds. Its text writes it throughfield.types, and so does Arrow (see duckdb_types_arrow).TIME_NSreads through Arrow, and to the microsecond through a cast toTIMEin the query. Its text writes it, and so does Arrow.TIMETZ(TIME WITH TIME ZONE) reads as thedifftimeof its local time. The offset it drops is a limitation. Its text writes it.TIMESTAMP_S,TIMESTAMP_MS,TIMESTAMP(DATETIME) read asPOSIXct.POSIXctwritesTIMESTAMP, the instant in UTC, andfield.typesnames the other precisions.TIMESTAMP_NSreads asPOSIXct.POSIXctwrites it to the microsecond throughfield.types, and Arrow writes it directly.TIMESTAMPTZ(TIMESTAMP WITH TIME ZONE) reads asPOSIXct.POSIXctwrites the plainTIMESTAMPof the same instant;field.typesmakes itTIMESTAMPTZ, and Arrow writes it directly.INTERVALreads asdifftimein seconds, counting a month as 30 days and a day as 24 hours. Adifftimein any unit, or anhms, writesINTERVAL.
Enums and nested types
The enum type, and the nested ones:
ENUMreads asfactor, with every value of the type as a level. Afactorororderedcolumn writesENUMof its levels; afactorparameter binds asVARCHAR.ARRAY(INTEGER[3]) reads witharray = "matrix", as a matrix with a row per value. A matrix column writes it.LIST(INTEGER[]) reads as a list of vectors,NULLfor aNULLrow, and a list column whose elements share a type writes it.MAPreads as a list ofdata.frame(key, value), which writes a list of structs unlessfield.typesnames the map. Withmap = "list_of", thevctrs::list_of()it reads as writes back asMAPwithoutfield.types(#200), and a list column of named lists writes a list of structs, an entry per name, valued by the first element of the name's value, or byNULLwhere that value isNULLor empty. Its text casts toMAPin the query and as a parameter.STRUCT(ROW) reads as a data frame column. A data frame column writes it, and a data frame parameter binds a struct per row.UNIONreads in the query throughunion_tag(),union_extract()or a cast toVARCHAR, and an Arrow result carries it. A column of a member's type writes it throughfield.types, which picks that member; text picks theVARCHARmember.VARIANTreads as a list, each value converted by its own type. A column of the value's type writes it throughfield.types.
Geometry
The GEOMETRY type, its coordinate reference system (CRS),
and the spatial extension's own types:
GEOMETRYreads as WKB. Withgeometry = "blob", the default, it reads as a list of raw vectors; withgeometry = "wk", aswk_wkb, carrying the column's CRS as an attribute, whichsf::st_as_sfc()converts onward, CRS included. The type is core since DuckDB 1.5, so reading one needs no extension; the geometry functions are thespatialextension's. Arrow carries the column as GeoArrow WKB with its CRS, in both directions (see duckdb_types_arrow).WKT writes
GEOMETRY. Acharactercolumn of WKT, assf::st_as_text()makes it, writes aGEOMETRYcolumn withfield.types = c(geom = "GEOMETRY")and appends to one withdbAppendTable(), because the cast fromVARCHARparses WKT. Naming the CRS in the type, as"GEOMETRY('EPSG:4267')", gives the column its CRS. Writing WKB as raw vectors, ansfobject or ansfccolumn is a limitation.The
spatialextension's own types are aliases, and read as what they alias.POINT_2D,POINT_3D,POINT_4D,BOX_2DandBOX_2DFare structs, and read as data frame columns;LINESTRING_2DandLINESTRING_3Dare lists of point structs, and read as lists of data frames;POLYGON_2DandPOLYGON_3Dare lists of those rings, and read as lists of lists;WKB_BLOBis aBLOB, and reads as raw vectors. The same shapes write the plain struct or list, andfield.typesnaming the alias casts back to it. They cast toGEOMETRYin the query, and the point, linestring, polygon and WKB types cast from it, as'POINT (1 2)'::GEOMETRY::POINT_2D.
Everything else
An untyped
NULLcomes back asNA_integer_, matching the engine's ownSELECT NULL; mapping it to logicalNAinstead was declined (#155). A typedNULL, as a scanned logical column or a boundNAparameter, round-trips as logicalNA.JSON, thejsonextension's alias ofVARCHAR, reads ascharacter. Its text writes it throughfield.types.INET, theinetextension's address type, reads as a data frame column whoseaddressis aHUGEINTread as a double, exact for IPv4; an IPv6 address is a limitation. Its text reads and writes it exactly.
Limitations and reference
The limitations are listed in the handbook, in usage/types/.
The mapping is implemented in src/types.cpp (R vector to LogicalType) and src/transform.cpp (the way back).
The list of types is DuckDB's own documentation for the release vendored here,
and every entry on this page was measured on DuckDB 1.5.5, in experiments/2026-09-26-type-catalog/,
experiments/2026-09-27-review-limits/,
experiments/2026-09-28-type-rereview/
or, for geometry route by route, experiments/2026-08-09-spatial-interop/.
Which zone labels a timestamp is documented in the handbook's timestamps/.
What expr_constant(NA) builds in the relational API is documented in the handbook's relational/.