CapyDB Docs
GuidesIntegrations

Clerk auth sync

Mirror your Clerk users into a capydb_auth.users table in your own database, so user data is one JOIN away.

The problem it solves

Clerk holds your users; your database holds everything else. Every "show me orders with customer emails" query turns into an API call plus app-side stitching. Auth sync ends that: CapyDB maintains a capydb_auth.users table inside your project database, kept current from Clerk, so user data is plain SQL.

SELECT o.id, o.total, u.email
FROM orders o
JOIN capydb_auth.users u ON u.id = o.user_id
WHERE u.deleted_at IS NULL;

Setup

Dashboard → project → Settings → Integrations → Clerk:

  1. Enter your Clerk secret key (sk_live_... / sk_test_...). Stored encrypted, never returned.
  2. CapyDB creates the capydb_auth schema and users table in your database and backfills all existing users from the Clerk API.
  3. To keep it fresh, create a webhook endpoint in the Clerk dashboard (Configure → Webhooks) pointing at:
https://capydb.dev/api/capydb/v1/integrations/clerk/webhook/{projectID}

subscribed to user events, and paste the endpoint's Svix signing secret (whsec_...) into the CapyDB integration. Without the webhook secret the sync is backfill-only — it will not follow ongoing changes.

The table

capydb_auth.users (
  id              text primary key,   -- Clerk user id
  email           text,               -- primary email address
  first_name      text,
  last_name       text,
  username        text,
  image_url       text,
  created_at      timestamptz,
  updated_at      timestamptz,
  last_sign_in_at timestamptz,
  deleted_at      timestamptz,        -- soft delete; rows are kept
  raw             jsonb               -- the full Clerk user object
)
  • Deletions in Clerk set deleted_at instead of removing the row, so foreign keys and history survive. Filter with WHERE deleted_at IS NULL.
  • Anything not covered by the typed columns is in raw — public metadata, external accounts, the lot.

Ground rules

  • Treat the table as read-only: the sync upserts over it, and your manual edits will be overwritten on the next event for that user. Reference it; do not write to it.
  • The sync writes through the project's own connection. It coexists with your schema; nothing else in your database is touched.
  • Webhook deliveries from Clerk are verified against the Svix signing secret you provided; unsigned or mis-signed deliveries are rejected.

Not on Clerk?

The same capydb_auth.users table works with Auth0 and Better Auth — identical shape and ground rules, different webhook verification. Clerk is the only provider with an API backfill of existing users; the others are webhook-only.