Prevent Duplicate Emails in FaunaDB Using a Unique Index
FaunaDB has no column-level unique constraint. Use a unique index to reject duplicate writes at the database layer, and handle the error in your application.
29 Mar 2026, 00:13 UTC

The problem: duplicate signups slip past application checks
Imagine a signup form that asks for an email address. Your application checks whether the email already exists before inserting a new user record. Between that check and the write, another request can register the same address. FaunaDB does not offer traditional column-level unique constraints, so an application-level pre-check is not enough to guarantee uniqueness.
The useful takeaway: create a unique index on the email field. FaunaDB rejects any write that would duplicate an indexed term, and your application can catch that database error and return a validation message.
How a unique index works in FaunaDB
In FaunaDB, a collection is similar to a table, and an index lets you look up documents by a field value. A unique index adds a rule: no two documents in the collection may have the same value for the indexed term. If a write would violate that rule, FaunaDB rejects it.
A single unique index can do double duty. It enforces uniqueness and also serves as a lookup index, so you do not need a separate index just to find a user by email.
Worked example: unique email with case normalization
Run this in the Fauna Shell, Fauna Dashboard, or through a client SDK with an admin or server key that has permission to create indexes. Replace users with your collection name.
// 1. Ensure the collection exists.
// CreateCollection({ name: 'users' })
// 2. Create a unique index on email, lowercasing the value first.
// CreateIndex({
// name: 'unique_user_email',
// source: Collection('users'),
// terms: [{ field: ['data', 'email'] }],
// unique: true,
// bindings: {
// email_lower: Query(Lambda('doc', LowerCase(Select(['data', 'email'], Var('doc')))))
// }
// })
terms tells FaunaDB which field to index. unique: true turns on the uniqueness rule. The binding normalizes the email to lowercase so that [contact removed] and [contact removed] are treated as the same value.
Before creating the index, check that no existing documents already share an email. FaunaDB will refuse to create a unique index if duplicate values are already present. You must deduplicate or backfill those records first.
Write and handle the duplicate
Insert a document normally. If a second write attempts the same email, FaunaDB rejects the write. Your application should catch the error from the Fauna client SDK and convert it into a user-facing message such as "This email is already registered."
Do not rely only on a pre-write lookup. Because the violation happens at write time, two concurrent requests can both pass a lookup and then collide at the database. Handling the database error directly closes that race.
Limitations and what to verify first
- Existing duplicates block index creation. Scan the collection for repeated email values before you create the unique index.
- FaunaDB FQL syntax and error shapes vary between releases. Confirm the syntax for your target FaunaDB version before adopting this pattern.
- FaunaDB service availability and support timelines can change. Check Fauna’s official status page for your target region before beginning new development.
Practical check
- Create the collection and unique index as shown above.
- Write one document with an email address.
- Attempt a second write with the same email, using different casing if you added a lowercase binding.
- Confirm the second write is rejected and inspect the SDK error to verify it maps to a unique-violation or duplicate-term condition.
This example is a pattern, not a tested production script. Adapt the field paths and error handling to your SDK and schema.
Closing
Start with the unique index, not the application check. Create it on an empty or deduplicated collection, normalize values with bindings if you need case-insensitive uniqueness, and handle the write error in your code. Verify the behavior with a duplicate-write test before you deploy.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.