Unique username with DCB
A 15 minute tutorial for global uniqueness
Let’s build a simple registration flow where usernames are globally unique. No sagas. No compensation. Just DCB.
What you will build
Section titled “What you will build”- A
UserRegisteredevent with ausername:tag - A DCB read that checks for collisions
- A conditional append that enforces uniqueness
Step 1: Define the event
Section titled “Step 1: Define the event”type UserRegistered = { type: 'UserRegistered'; data: { userId: string; username: string; }; tags: string[];};Step 2: Build the tag
Section titled “Step 2: Build the tag”const tag = `username:${username.toLowerCase()}`;Step 3: Read by query
Section titled “Step 3: Read by query”const query = { items: [ { types: ['UserRegistered'], tags: [tag], }, ],};
const { events, lastPosition } = await eventStore.readByQuery({ query, after: 0,});If events.length > 0, the username is already taken.
Step 4: Append with condition
Section titled “Step 4: Append with condition”const event: UserRegistered = { type: 'UserRegistered', data: { userId, username }, tags: [tag],};
await eventStore.append([event], { failIfEventsMatch: query, after: lastPosition,});If someone else registers the same username after you read, the append fails. That is the boundary doing its job.
Step 5: Handle conflicts
Section titled “Step 5: Handle conflicts”try { await eventStore.append([event], { failIfEventsMatch: query, after: lastPosition, });} catch (error) { if (isAppendConditionError(error)) { throw new Error('Username already taken'); } throw error;}What you just built
Section titled “What you just built”- A global uniqueness constraint
- A single event that represents the fact
- A DCB write that rejects conflicts without sagas
If you want to go deeper, read the DCB concept doc or the uniqueness guide.