Your users table is chaos
May 26, 2026
Self-serve means your users table is chaos. When anyone can sign up with any email address, the users table is inevitably polluted with throwaway emails. Self-serve users to orgs is a many-to-many relationship, so this means your orgs table is also chaos: users will create throwaway orgs to test out your product.
Yet financial/legal/support relationships require organization. A company has employees and you owe those employees fast replies, SLAs, etc. For instance, when someone asks us a question via our support@ email, we’d like to be able to route and prioritize it based on their subscription/support contract. And we don’t want to require their finance team to signup for Kernel to ask for an invoice.
You want to sync over your orgs and users emails over to your GTM tools. This should add context without chaos. Your CRM or support queue only touches a portion (~20%) of customers. It makes more sense to sync that portion, instead of trying to sync everyone. Philosophically, tools are for workflow and databases, for systems-of-record. We should only sync over what is needed, not seek to replicate the chaos of self-serve signups into our workflow. Especially because with webhooks, you fill in the details within seconds of a new support ticket or deal coming in, it’s much better to be just-in-time.
As another note, databases are fast and APIs are slow. A complex join read from a database might take a few milliseconds, whereas you’d often need to make multiple API requests taking 100+ milliseconds each with rate limiting. This isn’t huge, but as you sync thousands of customer accounts, the latency increases the risk of race conditions, as SaaS products never offer “locks”.
To do (sane) sync, you need primary keys. For accounts, the key is domain(s); for users, email(s).
Domains
Domain(s) map to org, account, or company. While some domains will exist across multiple orgs, you can usually decide on “primary” org for each domain. We should have domain “tombstones” to mark cases where a domain should not be included in that org. In case where an org has multiple domains, the newest domain should be considered the primary domain. Track this with a unique domain to org id to SaaS id table.
Picking the primary org should have a few heuristics:
- Verified domains (see Clerk)
- Paid tier (the higher, the more primary)
- More users from that domain
- Recency (more recently used)
Emails
Email(s) map to user, contact, or people. While emails are enforced as unique in Kernel, users might be part of multiple orgs. Like domain, there is always a primary org for business purposes and mapping to that is sufficient. Track this with a unique email to user id to SaaS id table.
Tombstones
There are always exceptions to every rule. Alerting on cases where a domain or user could be associated with multiple orgs (where both orgs are legit) and creating “tombstones” to disassociate a domain-org or user-org connection. Both domain and email tables should have a “tombstone” array type column, each within a GIN index for fast membership querying.
Consolidation
Domain/email drift can happen in two directions: SaaS added a new contact or Kernel has added a new user. When a new contact is added in the SaaS app, we should attempt to find its matching account. If a new user is added in Kernel, we should attempt to link it to existing SaaS contacts. If we fail to find a link, no-op.
Deletion
If a user membership is removed from an org, recalculate and reassign. If a user is deleted, we simply leave those contacts as unassigned to an account. In Pylon, deleting a contact will delete underlying issues.
Webhooks
To do this, we need triggers from our GTM tools, billing, and product (user org membership or email changes).

