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; caldav enables both CalDAV and CardDAV
- Configuration reference — full bext.config.toml field 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 .vcf contact files