Unique Constraints
Guarantee that a field's value is unique across a collection — no two users with the same email, no duplicate slugs — enforced by the database itself.
Declaring a constraint
Constraints are declared per collection from the dashboard. Open the collection, click Constraints, enter the field name (e.g. email), optionally mark it case-insensitive, and add it. From that point, every write to the collection is checked.
One field in the dashboard, composite-ready underneath
Case-insensitive uniqueness
For values like emails and usernames, enable case-insensitive when declaring the constraint. The database then treats values that differ only in case as the same — [email protected] and [email protected] cannot both exist.
Enforcement
Any insert, update, or upsert that would create a duplicate is rejected with a conflict. In the SDK, catch KoolbaseConflictException:
try {
await Koolbase.db.collection('users').insert({
'email': email,
'name': name,
});
} on KoolbaseConflictException {
showError('That email is already registered.');
}React Native and Web
@koolbase/react-native and @koolbase/js — throw KoolbaseConflictError on the same conflict — catch it with e instanceof KoolbaseConflictError. (There, conflicts surface on upsert; insert and update are optimistic and sync in the background.)Upsert becomes atomic
When an upsert's match fields are backed by a unique constraint, the operation is race-free: the constraint makes a duplicate impossible, so two simultaneous upserts on the same key resolve to one insert and one update rather than two rows.
// 'email' has a unique constraint -> this upsert is atomic
final result = await Koolbase.db.upsert(
collection: 'profiles',
match: {'email': email},
data: {'last_seen': DateTime.now().toIso8601String()},
);
print(result.created); // true if inserted, false if updatedWithout a covering constraint, upsert is best-effort — still a single server call, but two concurrent inserts could race. Declaring the constraint is what makes it fully race-free.
Adding a constraint to existing data
If the collection already contains records that would violate the constraint, declaring it is refused and the conflicting values are reported back to you. Koolbase never merges or deletes records on your behalf — resolve the duplicates first, then declare the constraint.
Empty and missing values are not constrained
null are not subject to the constraint — you can have many records without the field. Uniqueness applies only among records that actually have a value. Soft-deleting a record also frees its value, so the same value can be used again afterward.