Procedure: Create Sidecar Records
Create two records with different collection NSIDs but the same rkey, linking them together by key.
Lexicon type: procedure
function handle()
local rkey = TID()
local post = Record("xyz.statusphere.post", {
text = input.text,
createdAt = now(),
})
post:set_rkey(rkey)
local metadata = Record("xyz.statusphere.postMetadata", {
lang = input.lang or "en",
source = input.source or "web",
createdAt = now(),
})
metadata:set_rkey(rkey)
Record.save_all({ post, metadata })
return {
post = { uri = post._uri, cid = post._cid },
metadata = { uri = metadata._uri, cid = metadata._cid },
}
end
How it works
- Generate a single
TID()to use as the rkey for both records. - Create a
Recordfor each collection and callr:set_rkey()with the shared rkey. - Save both records in parallel with
Record.save_all(). - Return both URIs so the client knows the identity of each record.
Usage
curl -X POST http://localhost:3000/xrpc/xyz.statusphere.createPost \
-H "X-Client-Key: $CLIENT_KEY" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "text": "Hello world", "lang": "en", "source": "web" }'
The response includes URIs for both the post and its metadata:
{
"post": {
"uri": "at://did:plc:abc/xyz.statusphere.post/3abc123",
"cid": "bafyrei..."
},
"metadata": {
"uri": "at://did:plc:abc/xyz.statusphere.postMetadata/3abc123",
"cid": "bafyrei..."
}
}
Use case
Sidecar records are useful when you want to associate related data across collections without embedding everything in a single record. Because they share an rkey, you can derive one URI from the other:
at:// did:plc:abc /xyz.statusphere.post /3abc123
at:// did:plc:abc /xyz.statusphere.postMetadata /3abc123
^^^^^^^ same rkey
This is a common atproto pattern for keeping a primary record lean while storing auxiliary data (metadata, reactions, settings) in a companion collection.