CardDAV (Contacts Sync)
bext can serve as a CardDAV server (RFC 6352), enabling contacts synchronization with standards-compliant clients — Apple Contacts, Thunderbird, GNOME Contacts, DAVx5, and others. It shares the same WebDAV foundation and storage backend as CalDAV.
Enabling CardDAV#
CardDAV is enabled through the same [caldav] config section, since both
protocols share the WebDAV stack and storage:
[caldav]
enabled = true
storage = "memory" # "memory" | "pg"
# For PostgreSQL storage
# storage = "pg"
# pg_url = "postgresql://user:pass@localhost/bext_dav"
Compile with the caldav feature flag:
bext build --features caldav
When [caldav] is enabled, both CalDAV and CardDAV endpoints are active.
WebDAV Foundation#
CardDAV uses the same WebDAV methods as CalDAV:
| Method | Purpose |
|---|---|
PROPFIND |
Read properties of address books and contacts. |
PROPPATCH |
Modify address book properties. |
REPORT |
Run queries (text search, multiget, sync). |
MKCOL |
Create a new address book collection. |
PUT |
Create or update a contact. |
GET |
Retrieve a single contact (.vcf). |
DELETE |
Remove a contact or address book. |
URL Structure#
Address book collections follow a predictable hierarchy:
/addressbooks/{user}/ # User's address book home
/addressbooks/{user}/{book}/ # A specific address book
/addressbooks/{user}/{book}/{uid}.vcf # A single contact
Example:
/addressbooks/alice/contacts/
/addressbooks/alice/contacts/bob-smith.vcf
/addressbooks/alice/team/
vCard Format#
Contacts are stored as vCard 4.0 (RFC 6350) .vcf files. bext parses
and validates them on PUT:
BEGIN:VCARD
VERSION:4.0
FN:Bob Smith
N:Smith;Bob;;;
EMAIL;TYPE=work:bob@example.com
TEL;TYPE=cell:+1-555-0123
ADR;TYPE=home:;;123 Main St;Springfield;IL;62701;US
ORG:Acme Corp
END:VCARD
Supported vCard properties include:
| Property | Description |
|---|---|
FN |
Formatted (display) name. |
N |
Structured name components. |
EMAIL |
Email addresses with type labels. |
TEL |
Phone numbers with type labels. |
ADR |
Postal addresses with type labels. |
ORG |
Organization name. |
PHOTO |
Contact photo (URI or inline base64). |
BDAY |
Birthday. |
NOTE |
Free-text notes. |
CardDAV Reports#
Clients query address books using REPORT requests. bext supports three report types:
addressbook-query#
Search contacts by property value:
<card:addressbook-query xmlns:card="urn:ietf:params:xml:ns:carddav">
<d:prop xmlns:d="DAV:">
<d:getetag/>
<card:address-data/>
</d:prop>
<card:filter>
<card:prop-filter name="EMAIL">
<card:text-match collation="i;unicode-casemap"
match-type="contains">example.com</card:text-match>
</card:prop-filter>
</card:filter>
</card:addressbook-query>
addressbook-multiget#
Fetch specific contacts by URL in a single request:
<card:addressbook-multiget xmlns:card="urn:ietf:params:xml:ns:carddav">
<d:prop xmlns:d="DAV:">
<d:getetag/>
<card:address-data/>
</d:prop>
<d:href>/addressbooks/alice/contacts/bob-smith.vcf</d:href>
<d:href>/addressbooks/alice/contacts/carol-jones.vcf</d:href>
</card:addressbook-multiget>
sync-collection#
Efficient incremental sync (RFC 6578), identical to CalDAV's sync mechanism. The client sends a sync token and receives only changes:
<d:sync-collection xmlns:d="DAV:">
<d:sync-token>data:,67890</d:sync-token>
<d:prop>
<d:getetag/>
</d:prop>
</d:sync-collection>
Discovery#
Clients discover CardDAV using the .well-known redirect (RFC 6764):
GET /.well-known/carddav
→ 301 /addressbooks/
bext registers this redirect automatically when CardDAV is enabled. Client apps only need the server hostname to find the address book home.
Shared Storage Backend#
CardDAV shares its storage backend with CalDAV — both use the [caldav]
config section and the same database tables. See the
CalDAV docs for storage backend details.
Authentication#
CardDAV endpoints require authentication, using the same middleware as all other bext routes:
[[routes]]
path = "/addressbooks/*"
auth = "required"
The {user} in the URL path is matched against the authenticated
identity. Users can only access their own address books unless granted
explicit sharing permissions.
Configuration#
CardDAV uses the [caldav] configuration section. Contact-specific
limits:
[caldav]
enabled = true
storage = "pg"
pg_url = "postgresql://user:pass@localhost/bext_dav"
max_contact_size_bytes = 65536
max_contacts_per_book = 100000
| Field | Default | Description |
|---|---|---|
max_contact_size_bytes |
65536 | Max size of a single .vcf upload. |
max_contacts_per_book |
100000 | Safety limit per address book. |
Feature Flag#
CardDAV requires the caldav feature flag (shared with CalDAV):
bext build --features caldav
CardDAV is enabled automatically whenever [caldav] is enabled — there
is no separate feature flag or config toggle. Disabling contacts while
keeping calendars is not currently supported; both share the same WebDAV
stack and are always activated together.
The memory storage backend loses all contact data on restart. Use
storage = "pg" in any production deployment. The database schema is
shared with CalDAV — a single PostgreSQL instance and pg_url covers
both protocols.
Related#
- CalDAV (Calendar Sync) — companion protocol sharing the same WebDAV stack and storage backend
- Auth capability — authentication middleware applied to
/addressbooks/*routes - Build flags — compile-time feature flags;
caldavenables both CalDAV and CardDAV - Configuration reference — full
bext.config.tomlfield reference
Links#
- RFC 6352 — CardDAV: vCard Extensions to WebDAV — the CardDAV protocol specification
- RFC 6350 — vCard Format Specification — the vCard 4.0 format used for
.vcfcontact files