Couchbase views are a relic of Couchbase’s early days, and while they worked, they were often a performance bottleneck and difficult to manage. The primary reason to migrate away from them is that GSI (Global Secondary Indexes) offer a fundamentally more efficient and scalable way to query your data.

Let’s see a view in action, and then we’ll contrast it with how GSI handles the same query.

Here’s a simple view definition in JavaScript, designed to find all users with a specific role:

function (doc, meta) {
  if (doc.type === 'user' && doc.role) {
    emit(doc.role, null);
  }
}

To query this view for users with the role admin, you’d use an HTTP request like this:

GET /my_bucket/_design/users/_view/by_role?key="admin"

This query triggers a map-reduce process. Couchbase first executes the map function for every document in the my_bucket. For documents that match the if condition, it emits a key-value pair. Then, for views with a reduce function (even if it’s the default _count), Couchbase aggregates these emitted pairs. This entire process happens on the fly for each query, or if the view is stale, it might trigger a background rebuild.

Now, let’s look at the GSI equivalent. First, we need to create a GSI index. This index is built once and maintained incrementally as documents are added, updated, or deleted.

couchbase-cli gsi-tool create-index \
  --cluster localhost:8091 \
  --username Administrator \
  --password password \
  --bucket my_bucket \
  --index-name users_by_role \
  --index-definition '{"using": "gsi", "index_key": ["role"], "eq_freetext": ["role"]}'

This command creates an index named users_by_role on my_bucket. The index_key specifies that we want to index the role field. eq_freetext is a common choice for equality lookups.

To query this GSI index for users with the role admin, you’d use N1QL:

SELECT *
FROM my_bucket
WHERE role = "admin";

This N1QL query, when executed, directly uses the users_by_role GSI. Couchbase doesn’t need to scan every document or run a JavaScript function. It goes directly to the index, finds the entries where role is "admin", and retrieves the corresponding document IDs. It then fetches those documents from the primary index or directly if the index is covering.

The core problem views solve is providing a way to query data without knowing the primary key beforehand. They allow you to derive queryable keys from document content. GSI indexes are the modern evolution of this concept. Instead of running arbitrary JavaScript, GSI indexes are built on a more structured, efficient data structure optimized for lookups.

When you create a GSI index, Couchbase builds a persistent, on-disk data structure. This structure is specifically designed for fast key lookups. As documents change, Couchbase updates the index in real-time. This means queries against GSI indexes are significantly faster because they bypass the overhead of JavaScript execution, map-reduce aggregation, and incremental view building.

The index_key in the GSI definition is crucial. It tells Couchbase which fields to include in the index and in what order. For simple equality lookups, like our role = "admin" example, indexing the role field directly is optimal. If you frequently query by multiple fields, like role and status, you’d define a composite index: ["role", "status"].

The surprising thing most people miss about GSI indexes is how they handle data types and null values. Unlike views, where null keys might be treated inconsistently or require explicit handling in the map function, GSI indexes are generally very good at indexing null values. If you create an index on a field and some documents have that field as null or missing, the GSI will create entries for those nulls. This means you can query for documents where a field is null using N1QL like WHERE role IS NULL, and it will efficiently use the index.

Migrating from views to GSI indexes isn’t just about performance; it’s about leveraging a more robust, scalable, and maintainable indexing strategy. The next challenge you’ll likely face is optimizing your N1QL queries to fully utilize these new GSI indexes.

Want structured learning?

Take the full Couchbase course →