Couchbase Scopes and Collections: A Practical Path to Multi‑Tenant Isolation
Couchbase 7.0 introduced Scopes and Collections, a three‑level hierarchy that lets you isolate tenants, indexes, and permissions inside a single bucket—no more bucket sprawl or giant type‑field indexes.
16 Aug 2025, 18:09 UTC

The problem: one bucket, many tenants
In a SaaS product you often start with a single Couchbase bucket and a type field to separate customers. As the tenant count grows, that field becomes a bottleneck: every query scans the whole bucket, indexes swell, and a single misbehaving tenant can starve RAM or I/O for everyone else. Creating a new bucket per tenant solves isolation but explodes operational overhead—each bucket needs its own RAM quota, replication stream, and backup job.
What Scopes and Collections change
Since Couchbase 7.0 the data model has three levels: bucket → scope → collection. A bucket can hold up to 1,000 scopes, each scope up to 1,000 collections (10,000 total). Collections share the bucket’s RAM quota and replication topology but get independent indexes, compaction schedules, and statistics. The old flat model is still there—every bucket ships with a _default scope and _default collection—so existing code runs unchanged.
Logical grouping without extra buckets
You can map each tenant to its own collection (or a scope per business unit with collections per service). N1QL references become bucket.scope.collection, so a query for tenant A never touches tenant B’s documents. Indexes built on a collection only contain that tenant’s keys, cutting scan cost dramatically compared to a global type index.
Fine‑grained RBAC
Roles can be granted at the collection level. A microservice team receives query_select on app.tenantA.orders and nothing else in the same bucket. The admin UI or couchbase-cli user-manage lets you create a role like:
couchbase-cli user-manage -c localhost:8091 -u admin -p secret \
--set --rbac-username tenantA_svc --rbac-password 'pwd' \
--roles 'query_select[app.tenantA.orders]'
Attempting SELECT * FROM app.tenantB.orders with that credential returns a permission error, confirming isolation.
Selective cross‑datacenter replication
XDCR still replicates at bucket level, but from 7.1 you can add a collectionFilters map to the replication reference. Only the listed collections stream to the remote cluster. This is useful when a disaster‑recovery site only needs a subset of tenants.
Worked example: onboarding a new tenant
- Create scope and collection (run on any node with cluster admin rights):
couchbase-cli collection-manage -c localhost:8091 -u admin -p secret \ --bucket app --create-scope tenant_42 \ --create-collection tenant_42.orders - Verify via N1QL (run in Query Workbench or
cbq):
Expect an empty result set initially—no documents yet, but the collection exists.SELECT META().id FROM `app`.`tenant_42`.`orders` LIMIT 1; - Add a tenant‑specific index:
CREATE INDEX idx_tenant42_orders_status \ ON `app`.`tenant_42`.`orders`(status) \ WHERE type = 'order'; - Grant least‑privilege role (as shown above). Test with a service account that only holds that role; any query against another collection fails.
Trade‑offs and limits you should know
- Metadata churn: Creating or dropping collections is a cluster‑wide metadata operation. Avoid doing it in a hot request path; batch tenant onboarding jobs instead.
- Hard ceiling: 10,000 collections per bucket. If you anticipate more than a few thousand tenants, plan a sharding strategy across buckets.
- Backup/restore granularity:
cbbackupmgrbacks up the whole bucket. Collection‑level restore arrived in 7.6; on older versions you must restore the bucket then drop unwanted collections. - Service maturity: Analytics and Eventing gained collection awareness at different releases. Verify the specific service version before relying on collection‑level filters.
Actionable next steps
- Audit your current bucket: count distinct
typevalues and estimate tenant growth. - Prototype a two‑scope layout (e.g.,
corefor shared reference data,tenant_per customer) in a dev cluster. - Run the
collection-managecommands above, then exercise N1QL and RBAC to confirm isolation. - Add collection‑level indexes for the top‑query patterns and measure latency vs. the old global index.
- If you use XDCR, upgrade both clusters to ≥7.1 and enable
collectionFiltersfor the replication reference. - Document the onboarding runbook (create scope/collection, index, RBAC) so new tenants can be added without manual admin work.
Scopes and Collections give you the logical separation of multiple buckets while keeping the operational simplicity of a single bucket. Adopt them incrementally—start with the noisiest tenants—and you’ll gain query performance, security boundaries, and replication flexibility without a bucket explosion.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.