Zoekt

  • Tier: Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed

Zoekt is an open-source search engine designed specifically to search for code.

With this integration, you can use exact code search instead of advanced search to search for code in GitLab. You can use exact match and regular expression modes to search for code in a group or repository.

Zoekt handles only code search and does not replace Elasticsearch or OpenSearch. For all other search scopes, including comments, commits, epics, issues, merge requests, milestones, projects, users, and wikis, Elasticsearch or OpenSearch is still required.

Version compatibility

Each GitLab version comes with a specific gitlab-zoekt-indexer and gitlab-zoekt chart version.

GitLab versiongitlab-zoekt-indexer versiongitlab-zoekt chart version
19.41.19.04.1.0
19.1 to 19.31.16.14.1.0
19.01.14.24.0.0
18.111.13.13.11.0
18.101.11.23.10.0
18.91.8.23.9.0
18.81.8.03.8.0
18.6 and 18.71.7.63.7.1

Install Zoekt

Prerequisites:

  • Administrator access.

To enable exact code search in GitLab, you must have at least one Zoekt node connected to the instance. The following installation methods are supported for Zoekt:

The following installation methods are available for testing, not for production use:

Search URLs for multiple nodes

Each Zoekt node registers a search URL with GitLab. For group and global searches, one node forwards the search to the other nodes at their search URLs. If you run more than one Zoekt node, each search URL must be reachable from GitLab and from every other Zoekt node.

A loopback address like http://localhost:6070 or http://127.0.0.1:6070 works only when all nodes share one network host. For example, Zoekt nodes in separate containers cannot reach each other at localhost. When a node cannot reach another node’s search URL, group and global searches can return no results without an error.

The Zoekt chart sets the search URLs for you. When you run the Zoekt container image without the chart, the search URL is GITLAB_ZOEKT_SEARCH_URL if set, or GITLAB_ZOEKT_SELF_URL otherwise. To check the search URL of each node, see check indexing status.

From the GitLab UI

Prerequisites:

To enable exact code search from the GitLab UI:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. Select the Enable indexing checkbox.
  5. Do one of the following:
    • To index all root namespaces, select the Index root namespaces automatically checkbox.
    • To index only specific top-level groups, see configure Zoekt in GitLab.
  6. Select Save changes.
  7. Wait until all replicas and indices are ready. For EnabledNamespace count in the gitlab:zoekt:info Rake task output, wait for a total above zero with without indices: 0 (for example, 8 (without indices: 0)). For Replicas count and Indices count, wait until ready is the only state listed (for example, ready: 8). For more information, see check indexing status.
  8. Select the Enable searching checkbox.
  9. Select Save changes.

Global code search returns results only from indexed repositories. If you select the Enable searching checkbox before the initial indexing finishes, global code search results are incomplete.

With Rake tasks

Prerequisites:

You can manage exact code search with Rake tasks.

To enable indexing and search, run this Rake task:

shell
gitlab-rake gitlab:zoekt:index

This task enables zoekt_indexing_enabled, zoekt_search_enabled, and zoekt_auto_index_root_namespace. RolloutWorker indexes all root namespaces automatically, and search becomes available when indices are ready. Until the initial indexing finishes, global code search results are incomplete.

To disable indexing and search, run this Rake task:

shell
gitlab-rake gitlab:zoekt:disable

This task disables both zoekt_indexing_enabled and zoekt_search_enabled.

Pause and resume indexing

To pause indexing (for example, during maintenance), run this Rake task:

shell
gitlab-rake gitlab:zoekt:pause_indexing

To resume indexing, run this Rake task:

shell
gitlab-rake gitlab:zoekt:resume_indexing

Estimate storage requirements

To estimate the storage required for your Zoekt nodes, run this Rake task:

shell
sudo gitlab-rake gitlab:zoekt:estimate_storage

For more information, see estimate storage requirements.

Retry indexing of failed repositories

To retry indexing all failed Zoekt repository records, run this Rake task:

shell
gitlab-rake gitlab:zoekt:reindex_failed_projects

This task moves all failed zoekt_repository records to pending state with retries_left set to 1, so they are picked up by the next indexing cycle.

To retry only specific projects, pass a comma-separated list of project IDs:

shell
gitlab-rake "gitlab:zoekt:reindex_failed_projects[1,2,3]"

Check indexing status

Prerequisites:

  • Administrator access.

Indexing performance depends on the CPU and memory limits on the Zoekt indexer nodes. To check indexing status:

Run this Rake task:

shell
gitlab-rake gitlab:zoekt:info

To have the data refresh automatically every 10 seconds, run this Rake task instead:

shell
gitlab-rake "gitlab:zoekt:info[10]"

In a Rails console, run these commands:

ruby
Search::Zoekt::Index.group(:state).count
Search::Zoekt::Repository.group(:state).count
Search::Zoekt::Task.group(:state).count

Sample output

The gitlab:zoekt:info Rake task returns an output similar to the following:

console
Exact Code Search
GitLab version:                                                  19.5.0
Enable indexing:                                                 yes
Enable searching:                                                yes
Pause indexing:                                                  no
Index root namespaces automatically:                             yes
Cache search results for five minutes:                           yes
Indexing CPU to tasks multiplier:                                1.0
Probability of random force reindexing (percentage):             0.25
Number of parallel processes per indexing task:                  1
Number of namespaces per indexing rollout:                       32
Offline nodes automatically deleted after:                       20m
Indexing timeout per project:                                    30m
Maximum number of files per project to be indexed:               500000
Maximum file size for indexing:                                  1MB
Maximum trigrams per file:                                       20000
Retry interval for failed namespaces:                            1d
Number of replicas per namespace:                                1
Maximum number of projects for legacy search:                    1000
Maximum number of process restarts within 15 minutes for nodes:  3
Number of pending indices to start indexing per node:            1

Nodes
# Number of Zoekt nodes and their status
Node count:                    2 (online: 2, offline: 0)
Last seen at:                  2026-10-28 14:32:41 UTC (less than a minute ago)
Max schema_version:            2602
Storage reserved / usable:     335 GiB / 999 GiB (33.53%)
Storage indexed / reserved:    279 GiB / 335 GiB (83.28%)
Storage used / total:          304 GiB / 1 TiB (29.69%)
Online node watermark levels:  2
  - normal: 2

Indexing status
Group count:                       46
# Number of enabled namespaces and their status
EnabledNamespace count:            46 (without indices: 0, rollout blocked: 0, with search disabled: 0)
Replicas count:                    46
  - ready: 46
Indices count:                     46
  - ready: 46
Indices watermark levels:          46
  - healthy: 46
Repositories count:                3812
  - ready: 3812
Tasks count:                       214
  - done: 214
Tasks pending/processing by type:  (none)
Storage buffer factor:             1.214× [dynamic (observed)]

Feature Flags (Non-Default Values)
Feature flags:  none

Feature Flags (Default Values)
Feature flags:  none

Node Details
Node 1 - gitlab-gitlab-zoekt-0:
  Status:                        Online
  # Must be reachable from GitLab and from every other Zoekt node.
  Search URL:                    http://gitlab-gitlab-zoekt-gateway.gitlab.svc.cluster.local:8080/nodes/gitlab-gitlab-zoekt-0.gitlab-gitlab-zoekt.gitlab.svc.cluster.local
  Index URL:                     http://gitlab-gitlab-zoekt-gateway.gitlab.svc.cluster.local:8080/nodes/gitlab-gitlab-zoekt-0.gitlab-gitlab-zoekt.gitlab.svc.cluster.local
  Last seen at:                  2026-10-28 14:32:41 UTC (less than a minute ago)
  Disk utilization:              31.45%
  Unclaimed storage:             322 GiB
  # Zoekt build version on the node. Must match GitLab version.
  Zoekt version:                 2026.09.22-v1.19.2
  Schema version:                2602
Node 2 - gitlab-gitlab-zoekt-1:
  Status:                        Online
  Search URL:                    http://gitlab-gitlab-zoekt-gateway.gitlab.svc.cluster.local:8080/nodes/gitlab-gitlab-zoekt-1.gitlab-gitlab-zoekt.gitlab.svc.cluster.local
  Index URL:                     http://gitlab-gitlab-zoekt-gateway.gitlab.svc.cluster.local:8080/nodes/gitlab-gitlab-zoekt-1.gitlab-gitlab-zoekt.gitlab.svc.cluster.local
  Last seen at:                  2026-10-28 14:32:41 UTC (less than a minute ago)
  Disk utilization:              27.93%
  Unclaimed storage:             342 GiB
  Zoekt version:                 2026.09.22-v1.19.2
  Schema version:                2602

Process Health
Node 1 - gitlab-gitlab-zoekt-0:
  Indexer uptime:                   6d 3h 41m
  Indexer RSS memory:               1.18 GiB
  Indexer mmap (current/max, %):    412/262144 (0.2%) [OK]
  Indexer restarts (1m/5m/15m):     0 / 0 / 0
  Webserver uptime:                 6d 3h 41m
  Webserver RSS memory:             3.42 GiB
  Webserver mmap (current/max, %):  9418/262144 (3.6%) [OK]
  Webserver restarts (1m/5m/15m):   0 / 0 / 0
  Webserver loaded shards:          1184
  Webserver last reported:          2026-10-28 14:32:41 UTC (less than a minute ago)
Node 2 - gitlab-gitlab-zoekt-1:
  Indexer uptime:                   6d 3h 39m
  Indexer RSS memory:               1.06 GiB
  Indexer mmap (current/max, %):    398/262144 (0.2%) [OK]
  Indexer restarts (1m/5m/15m):     0 / 0 / 0
  Webserver uptime:                 2d 19h 7m
  Webserver RSS memory:             3.07 GiB
  Webserver mmap (current/max, %):  8305/262144 (3.2%) [OK]
  Webserver restarts (1m/5m/15m):   0 / 0 / 0
  Webserver loaded shards:          1043
  Webserver last reported:          2026-10-28 14:32:41 UTC (less than a minute ago)

When more than one node is online and at least one node has a loopback search URL, the Nodes section also shows a Loopback search URLs line. For example:

console
Loopback search URLs:          2 of 2 online nodes (reachable by other nodes only if all nodes share one network host)

For more information, see search URLs for multiple nodes.

Run a health check

Prerequisites:

  • Administrator access.

Run a health check to understand the status of your Zoekt infrastructure, including:

  • Online and offline nodes
  • Indexing and search settings
  • Search API endpoints
  • JSON web token generation

To run a health check, execute the following task:

shell
gitlab-rake gitlab:zoekt:health

This task provides:

  • The overall status: HEALTHY, DEGRADED, or UNHEALTHY
  • Recommendations for resolving detected issues
  • Exit codes for automation and monitoring integrations: 0=healthy, 1=degraded, or 2=unhealthy

Run checks automatically

To run health checks automatically every 10 seconds, execute the following task:

shell
gitlab-rake "gitlab:zoekt:health[10]"

The output includes colored status indicators and shows:

  • Online and offline node counts, storage usage warnings, and connectivity issues
  • Core settings validation and namespace and repository indexing statuses
  • The overall status including a combined health assessment: HEALTHY, DEGRADED, or UNHEALTHY
  • Recommendations for resolving issues

Force reindex projects

Prerequisites:

  • Administrator access.

To force reindex a range of projects, run this Rake task:

shell
gitlab-rake gitlab:zoekt:reindex_projects ID_FROM=10 ID_TO=20

ID_FROM and ID_TO represent the range of project IDs.

To force reindex only one project, use the same value for both ID_FROM and ID_TO. To force reindex all projects, do not use these environment variables.

Pause indexing

Prerequisites:

  • Administrator access.

To pause indexing for exact code search:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. Select the Pause indexing checkbox.
  5. Select Save changes.

When you pause indexing for exact code search, all changes in your repository are queued. To resume indexing, clear the Pause indexing for exact code search checkbox.

Index root namespaces automatically

Prerequisites:

  • Administrator access.

You can index both existing and new root namespaces automatically. To index all root namespaces automatically:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. Select the Index root namespaces automatically checkbox.
  5. Select Save changes.

When you enable this setting, GitLab creates indexing tasks for all projects in:

  • All groups and subgroups
  • Any new root namespace

After a project is indexed, GitLab creates only incremental indexing when a repository change is detected.

When you disable this setting:

  • Existing root namespaces remain indexed.
  • New root namespaces are no longer indexed.

Cache search results

Prerequisites:

  • Administrator access.

You can cache search results for better performance. This feature is enabled by default and caches results for five minutes.

To cache search results:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. Select the Cache search results for five minutes checkbox.
  5. Select Save changes.

Set concurrent indexing tasks

Prerequisites:

  • Administrator access.

You can set the number of concurrent indexing tasks for a Zoekt node relative to its CPU capacity.

A higher multiplier means more tasks can run concurrently, which would improve indexing throughput at the cost of increased CPU usage. The default value is 1.0 (one task per CPU core).

You can adjust this value based on the node’s performance and workload. To set the number of concurrent indexing tasks:

  1. In the upper-right corner, select Admin.

  2. In the left sidebar, select Settings > Search.

  3. Expand Exact code search.

  4. In the Indexing CPU to tasks multiplier text box, enter a value.

    For example, if a Zoekt node has 4 CPU cores and the multiplier is 1.5, the number of concurrent tasks for the node is 6.

  5. Select Save changes.

Define the probability of random force reindexing

Prerequisites:

  • Administrator access.

You can define the probability that a project is force reindexed instead of incrementally indexed. The default value is 0.25 (0.25%).

Force reindexing helps prevent memory map (mmap) handlers from running out by periodically rebuilding indices from scratch. A higher percentage increases indexing load, especially for very large repositories.

To define the probability of random force reindexing:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Probability of random force reindexing (percentage) text box, enter a number between 0 and 100.
  5. Select Save changes.

Set the number of parallel processes per indexing task

Prerequisites:

  • Administrator access.

You can set the number of parallel processes per indexing task.

A higher number would improve indexing time at the cost of increased CPU and memory usage. The default value is 1 (one process per indexing task).

You can adjust this value based on the node’s performance and workload. To set the number of parallel processes per indexing task:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Number of parallel processes per indexing task text box, enter a value.
  5. Select Save changes.

Set the number of namespaces per indexing rollout

Prerequisites:

  • Administrator access.

You can set the number of namespaces per RolloutWorker job for initial indexing. The default value is 32. You can adjust this value based on the node’s performance and workload.

To set the number of namespaces per indexing rollout:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Number of namespaces per indexing rollout text box, enter a number greater than zero.
  5. Select Save changes.

Set an initial indexing limit

Prerequisites:

  • Administrator access.

You can set how many pending indices start initial indexing on each Zoekt node every minute. The default value is 1, and the maximum value is 100.

With the default value, each node starts initial indexing for one pending index per minute. If you enable exact code search for many namespaces at once, such as during the first rollout, namespaces can wait hours before indexing starts. To start indexing sooner, increase this value. Higher values increase the load on Zoekt nodes and the database.

This setting is not available in the Admin area. To set an initial indexing limit:

  1. Start a Rails console session.

  2. Run this command:

    ruby
    ApplicationSetting.current.update!(zoekt_initial_indexing_limit: 100)

You can also modify the zoekt_initial_indexing_limit setting with the application settings API.

Define when offline nodes are automatically deleted

Prerequisites:

  • Administrator access.

You can delete offline Zoekt nodes automatically after a specific period of time along with their related indices, repositories, and tasks. The default value is 12h (12 hours).

Use this setting to manage your Zoekt infrastructure and prevent orphaned resources. To define when offline nodes are automatically deleted:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Offline nodes automatically deleted after text box, enter a value (for example, 30m (30 minutes), 2h (two hours), or 1d (one day)). To disable automatic deletion, set to 0.
  5. Select Save changes.

Define the indexing timeout for a project

Prerequisites:

  • Administrator access.

You can define the indexing timeout for a project. The default value is 30m (30 minutes).

To define the indexing timeout for a project:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Indexing timeout per project text box, enter a value (for example, 30m (30 minutes), 2h (two hours), or 1d (one day)).
  5. Select Save changes.

Set the maximum number of files in a project to be indexed

Prerequisites:

  • Administrator access.

You can set the maximum number of files in a project that can be indexed. Projects with more files than this limit on the default branch are not indexed. The default value is 500,000.

You can adjust this value based on the node’s performance and workload. To set the maximum number of files in a project to be indexed:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Maximum number of files per project to be indexed text box, enter a number greater than zero.
  5. Select Save changes.

Set maximum file size for indexing

Prerequisites:

  • Administrator access.

You can set the maximum size for a file to be indexed. The default value is 1MB.

For files that exceed the specified size, only filenames are indexed. You can search these files only by filename.

To set maximum file size for indexing:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Maximum file size for indexing text box, enter a value (for example, 512B, 50KB, 2MB, or 1GB). The value can also be in lowercase.
  5. Select Save changes.

Set the maximum trigram count for indexing

Prerequisites:

  • Administrator access.

You can set the maximum number of trigrams for a file to be indexed. The default value is 20,000.

Trigrams are three-character sequences that Zoekt uses for efficient code search. For files that exceed this trigram limit, only filenames are indexed. A higher limit affects both indexing and search performance.

To set the maximum trigram count for indexing:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Maximum trigrams per file text box, enter a number greater than zero.
  5. Select Save changes.

Define the retry interval for failed namespaces

Prerequisites:

  • Administrator access.

You can define the retry interval for namespaces that previously failed. The default value is 1d (one day). A value of 0 means failed namespaces never retry.

To define the retry interval for failed namespaces:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Retry interval for failed namespaces text box, enter a value (for example, 30m (30 minutes), 2h (two hours), or 1d (one day)).
  5. Select Save changes.

Set the number of replicas per namespace

Prerequisites:

  • Administrator access.

You can set the number of replicas per namespace. The default value is 1 (one replica per namespace).

Increasing the number of replicas per namespace improves search availability by distributing the load across multiple Zoekt nodes. More replicas increase storage requirements.

To set the number of replicas per namespace:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Number of replicas per namespace text box, enter a number greater than zero.
  5. Select Save changes.

Prerequisites:

  • Administrator access.

You can set the maximum number of projects to search in a group when traversal ID indexing is still in progress. The default value is 1,000.

When you search in a group before traversal ID indexing is complete, GitLab searches only the first projects (by project ID) up to this limit and shows a warning that some projects are not included in the results. After traversal ID indexing is complete, GitLab searches all projects in the group.

To set the maximum number of projects for legacy search:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Maximum number of projects for legacy search text box, enter a number greater than zero.
  5. Select Save changes.

Set the maximum number of process restarts for nodes

Prerequisites:

  • Administrator access.

You can set the maximum number of process restarts within 15 minutes before a node is excluded from search routing. The default value is 2.

GitLab uses this setting to detect crashlooping indexer or webserver processes. When a node has more process restarts within 15 minutes, the node is excluded from search until the restart count returns to range. A value of 0 means the node is excluded after a single restart.

If all online nodes are excluded, GitLab falls back to the full set of online nodes to avoid a search outage.

To set the maximum number of process restarts for nodes:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Settings > Search.
  3. Expand Exact code search.
  4. In the Maximum number of process restarts within 15 minutes for nodes text box, enter a number greater than or equal to zero.
  5. Select Save changes.

Run Zoekt on a separate server

Prerequisites:

  • Administrator access.

To run Zoekt on a different server than GitLab:

  1. Configure Gitaly to listen on TCP.
  2. Install Zoekt.

Configure Gitaly for an external Zoekt server

Zoekt indexes repositories by connecting to Gitaly, so Gitaly must listen on a TCP address the Zoekt server can reach. By default, Gitaly listens on a Unix socket, which is available only to processes on the same server.

The general instructions cover a multi-server installation. When Gitaly runs on the same server as GitLab and only Zoekt connects from outside, you need fewer settings.

gitaly['configuration'] replaces the entire Gitaly configuration hash instead of merging into it. If you already set custom Gitaly options, such as additional storages or TLS, merge this snippet into your existing configuration rather than pasting it as it is, and make sure name and path match your storage. For the same reason, keep the storage array even when you do not change the storage paths. Without it, Gitaly has no configured storage and repository access fails.

The configuration below also changes how Gitaly is reachable on the network.

listen_addr: '0.0.0.0:8075' makes Gitaly listen on all interfaces. Restrict access to port 8075 to the Zoekt server.

To configure Gitaly for an external Zoekt server:

  1. Generate a token:

    shell
    openssl rand -base64 24
  2. Edit /etc/gitlab/gitlab.rb and add the following, replacing <your_secure_token> with the generated token and <ip_address> with the address the Zoekt server uses to reach Gitaly:

    ruby
    # Shared token for Gitaly authentication
    gitlab_rails['gitaly_token'] = '<your_secure_token>'
    
    # Gitaly configuration
    gitaly['configuration'] = {
      listen_addr: '0.0.0.0:8075',
      auth: {
        token: '<your_secure_token>',
      },
      storage: [
        {
          name: 'default',
          path: '/var/opt/gitlab/git-data/repositories',
        },
      ]
    }
    
    # Tell Rails where to find Gitaly
    gitlab_rails['repositories_storages'] = {
      'default' => { 'gitaly_address' => 'tcp://<ip_address>:8075' },
    }
  3. Reconfigure GitLab:

    shell
    sudo gitlab-ctl reconfigure

After the reconfigure, Gitaly accepts TCP connections on port 8075 and the Zoekt server can reach it at the address you configured.

Sizing recommendations

The following recommendations might be over-provisioned for some deployments. You should monitor your deployment to ensure:

  • No out-of-memory events occur.
  • CPU throttling is not excessive.
  • Indexing performance meets your requirements.

Adjust resources based on your specific workload characteristics, including:

  • Repository size and complexity
  • Number of active developers
  • Frequency of code changes
  • Indexing patterns

Memory architecture

The webserver and indexer have different memory usage patterns.

The webserver memory-maps index shards from disk into virtual memory. The operating system pages shard data in and out of physical memory as searches are served. Resident memory usage grows with the active working set. Nodes with larger indices or higher query volume require more webserver memory to avoid page thrashing and out-of-memory conditions.

When the indexer builds or rebuilds indices, the indexer processes Git object data in memory. Memory usage spikes when large repositories are indexed or multiple tasks run in parallel. You can control peak indexer memory by adjusting the number of parallel processes per indexing task and concurrent indexing tasks.

On VM and bare metal deployments, the webserver and indexer share the same system memory.

Nodes

For optimal performance, proper sizing of Zoekt nodes is crucial. Sizing recommendations differ between Kubernetes and VM deployments due to how resources are allocated and managed.

Kubernetes deployments

The following table shows recommended resources per node (per StatefulSet pod) for Kubernetes deployments based on index storage requirements. Each pod in the StatefulSet runs its own webserver and indexer containers with independent resource allocations and its own persistent volume for index storage. If you run multiple nodes, multiply these resources by the number of nodes to calculate total cluster resources.

DiskWebserver CPUWebserver memoryIndexer CPUIndexer memory
128 GB116 GiB16 GiB
256 GB1.532 GiB18 GiB
512 GB264 GiB112 GiB
1 TB3128 GiB1.524 GiB
2 TB4256 GiB232 GiB

To manage resources more granularly, you can allocate CPU and memory separately to different containers.

For Kubernetes deployments:

  • Do not set CPU limits for Zoekt containers. CPU limits might cause unnecessary throttling during indexing bursts, which would significantly impact performance. Instead, rely on resource requests to guarantee minimum CPU availability and ensure containers use additional CPU when available and needed.
  • Set appropriate memory limits to prevent resource contention and out-of-memory conditions.
  • Use high-performance storage classes for better indexing performance. GitLab.com uses pd-balanced on GCP, which balances performance and cost. Equivalent options include gp3 on AWS and Premium_LRS on Azure.

VM and bare metal deployments

The following table shows recommended resources per node for VM and bare metal deployments based on index storage requirements. If you run multiple nodes, multiply these resources by the number of nodes to calculate total cluster resources.

DiskVM sizeTotal CPUTotal memoryAWSGCPAzure
128 GBSmall2 cores16 GBr5.largen1-highmem-2Standard_E2s_v3
256 GBMedium4 cores32 GBr5.xlargen1-highmem-4Standard_E4s_v3
512 GBLarge4 cores64 GBr5.2xlargen1-highmem-8Standard_E8s_v3
1 TBX-Large8 cores128 GBr5.4xlargen1-highmem-16Standard_E16s_v3
2 TB2X-Large16 cores256 GBr5.8xlargen1-highmem-32Standard_E32s_v3

You can allocate these resources only to the entire node.

For VM and bare metal deployments:

  • Monitor CPU, memory, and disk usage to identify bottlenecks.
  • Consider using SSD storage for better indexing performance.
  • Ensure adequate network bandwidth for data transfer between GitLab and Zoekt nodes.

Storage

Zoekt storage requirements depend on the size of your Git repositories and your replica configuration. Zoekt indexes only Git object data (source code and commit history). It does not index LFS files, CI/CD artifacts, packages, wikis, or other storage components.

Estimate requirements

To estimate storage requirements, run this Rake task:

shell
sudo gitlab-rake gitlab:zoekt:estimate_storage

This task queries your GitLab database and outputs a storage estimate based on your current repository sizes and replica configuration.

To calculate storage requirements manually, use these formulas instead:

storage_per_replica = sum(repository_git_size) × buffer_factor
total_cluster_storage = storage_per_replica × number_of_replicas

repository_git_size is the Git object size for each repository. This value does not include LFS objects, wikis, artifacts, or packages. buffer_factor is the headroom during initial indexing. You can calculate this value as Search::Zoekt::Index.global_buffer_factor, which is mostly 3 by default.

To view repository_git_size:

  1. In the upper-right corner, select Admin.
  2. In the left sidebar, select Overview > Projects.
  3. In the Repository column, view the Git object size.

For the initial provisioning target, start with three times your total repository_git_size multiplied by replica count. For example:

  • 100 GB of Git repository data and one replica: 300 GB of Zoekt storage.
  • 100 GB of Git repository data and two replicas: 600 GB of Zoekt storage.

GitLab reserves this buffer internally to ensure Zoekt has headroom during indexing. After initial indexing is complete, actual disk usage is typically closer to half the repository_git_size based on observed data on GitLab.com. Scale vertically or horizontally only when needed.

To view the current buffer factor, run this Rake task:

shell
sudo gitlab-rake gitlab:zoekt:info

The output includes Storage buffer factor, which shows the dynamic value the planner is using.

To monitor Zoekt node storage, see check indexing status. If namespaces are not indexed due to low disk space, add nodes or increase disk capacity.

Security and authentication

Zoekt implements a multi-layered authentication system to secure communication between GitLab, Zoekt indexer, and Zoekt webserver components. Authentication is enforced across all communication channels.

All authentication methods use the GitLab Shell secret. Failed authentication attempts return 401 Unauthorized responses.

Zoekt indexer to GitLab

The Zoekt indexer authenticates to GitLab with JSON web tokens (JWT) to retrieve indexing tasks and send completion callbacks.

This method uses .gitlab_shell_secret for signing and verification. Tokens are sent in the Gitlab-Shell-Api-Request header. The following endpoints are available:

  • GET /internal/search/zoekt/:uuid/heartbeat for task retrieval
  • POST /internal/search/zoekt/:uuid/callback for status updates

This method ensures secure polling for task distribution and status reporting between Zoekt indexer nodes and GitLab.

GitLab to the Zoekt webserver

JWT authentication

GitLab authenticates to the Zoekt webserver with JSON web tokens (JWT) to execute search queries. JWT tokens provide time-limited, cryptographically signed authentication consistent with other GitLab authentication patterns.

This method uses Gitlab::Shell.secret_token and the HS256 algorithm (HMAC with SHA-256). Tokens are sent in the Authorization: Bearer <jwt_token> header and expire in five minutes to limit exposure.

Endpoints include /webserver/api/search and /webserver/api/v2/search. JWT claims are the issuer (gitlab) and the audience (gitlab-zoekt).