GitLab exact code search with Zoekt

Zoekt gives self-managed GitLab exact match and regex code search, but it covers code only. This page explains the tier requirement, install paths, storage planning and the Elasticsearch or OpenSearch decision.

On this page

Why teams deploy GitLab exact code search with Zoekt

Zoekt gives developers exact-match and regex search across the code in a self-managed GitLab instance, and it is a Premium and Ultimate feature, generally available since GitLab 19.5. It searches code only. It does not replace advanced search for issues, merge requests, comments or other scopes, which still depends on Elasticsearch or OpenSearch. A team that keeps a large estate of repositories and needs developers to find a function name, a configuration key or a pattern across all of them is the usual case for planning this work. If your developers mostly search by project name or by a few known files, the feature may not justify the added infrastructure, so confirm the search patterns your teams actually use before committing.

Zoekt is an indexing engine that builds an index over repository contents, so queries return exact string and regular expression matches rather than the fuzzy, relevance-ranked results most search bars return. Deployment is done with the Zoekt Helm chart or the GitLab Operator, which means the search tier runs in the same Kubernetes footprint your GitLab installation uses. The tier is separate from the GitLab application, so capacity, upgrades and failure handling for the indexer need their own owner and their own runbook. Check the GitLab Zoekt documentation for the current supported combinations of chart, Operator and GitLab version before you pin a target.

The decision that drives the rest of the project is storage for initial indexing. GitLab sizes this at roughly three times the total Git size of your repositories, multiplied by the replica count, with steady-state usage closer to half the Git size. Ask your repository team for the total Git size across the instance, including large binary history, because that number, not the current code size, sets the disk budget. Plan the replica count and the disk class together, and confirm during scoping whether your storage platform can provision the volumes the index needs without a manual step.

Which tier and install path fit your instance

Exact code search with Zoekt is a Premium and Ultimate feature, so a Free instance cannot use it. Premium is the tier that carries the feature, and the GitLab pricing page lists Premium at 29 US dollars per user per month billed annually, which the vendor states applies to self-managed installations. Ultimate adds security and compliance features, so choose it only if those are needed for other reasons. Confirm with GitLab which tier includes each Zoekt capability before you commit.

  • Free instances: Zoekt is not available, so plan an upgrade or accept the built-in search.
  • Premium instances: Exact match and regex code search are included, which is the core reason most teams make this choice.
  • Ultimate instances: Zoekt is included, but pay for Ultimate only if its security and compliance features are needed.
  • Per-user cost: Licensing scales with user count, so a Premium quote should reflect your actual seat count.
  • Other search scopes: Elasticsearch or OpenSearch is still required for scopes Zoekt does not cover.

Check the licence tier against your current subscription and your planned user count before requesting a Zoekt deployment.

Configuration options and when each fits

This table compares the install method, replica count, indexing scope and the separate Elasticsearch or OpenSearch backend for Zoekt in self-managed GitLab. Read each row against your Kubernetes setup, expected search load and the repositories users must find. The main takeaway is that replica count and indexing scope both drive index storage, so confirm them before you size volumes.

OptionWhen it fitsTrade-off
Zoekt Helm chartYour team already manages GitLab and supporting services on Kubernetes with Helm values files.Your team owns the Zoekt release lifecycle and values alongside the rest of the cluster.
GitLab OperatorYou manage the GitLab instance declaratively with the GitLab Operator and want Zoekt in the same lifecycle.Confirm that your operator version and target GitLab release support the Zoekt deployment you plan.
Lower replica countA pilot, a smaller user base or search load where short interruptions to code search are acceptable.Less redundancy if a Zoekt node is lost, so confirm the failover behavior in the documentation.
Higher replica countMany concurrent searches or a requirement for code search to stay available during node maintenance.Initial indexing storage scales with the replica count, so each added replica adds capacity to plan.
Index all namespacesBroad code discovery across the whole instance where users expect every repository to be searchable.Largest index and the most repositories to index before results are complete for every group.
Index selected groups or projectsA phased rollout, or sensitive projects that need a deliberate decision before they are searchable.Users searching outside the indexed scope get no exact match results, so state the boundary to them.
Elasticsearch or OpenSearchAdvanced search across issues, merge requests, commits, wiki content or other non-code scopes.Zoekt does not cover these scopes, so plan, size and operate this backend separately with its own storage and versions.
Premium or Ultimate tierExact code search is a feature of these tiers, so the license decides whether this option exists for you.Confirm the tier and license terms with your GitLab account team before you commit to the design.

How much storage initial indexing needs

Plan for initial indexing to need roughly three times the total Git size of the repositories you will index, multiplied by the number of Zoekt replicas. Once indexing has settled, steady-state storage is closer to half the Git size, multiplied by the same replica count. The two figures answer different questions: the first sizes the disks you need on day one and during any full re-index, the second describes what the index typically occupies afterward. Size the volumes for the initial figure, not the steady-state one, or the first indexing run may fill them.

Illustrative example only: suppose your in-scope repositories total 200 GB of Git data and you run 2 replicas. Initial indexing would then call for roughly 3 × 200 GB × 2, or about 1.2 TB of index storage across the fleet. Steady state would be closer to 0.5 × 200 GB × 2, or about 200 GB. Your numbers will differ, so start by measuring the actual on-disk size of the repositories in scope, including the repositories that are not active but still searchable, and check the replica count in your deployment plan before you order disks.

Confirm both inputs with your GitLab administrator and your platform team before buying storage. Ask GitLab support or check the GitLab Zoekt documentation for the current sizing guidance, since the figures are the vendor's planning rule and not a guarantee for your repository mix. Add headroom for growth in repository count and for a full re-index after an upgrade or a configuration change, and make sure the storage class you choose can be expanded later without rebuilding the index.

Deploying Zoekt in a self-managed GitLab instance

This sequence takes a self-managed GitLab instance from a tier and version check to verified exact and regex code search powered by Zoekt. Each step ends with a check, so the team knows the indexer and web components are ready before developers depend on search results.

  1. Confirm tier and GitLab version

    Confirm that your instance runs GitLab 19.5 or later and that your license covers Premium or the tier above it, since exact code search with Zoekt is a feature of those tiers. Record the exact version from the instance's administration area and compare it with the upgrade stops in your plan. If you are on an earlier version, plan the upgrade path first, because the feature is not generally available before 19.5. Done when the version and license tier are written down and both meet the requirement.

  2. Choose the Helm chart or Operator path

    Pick the deployment method that matches how your team already runs GitLab. Zoekt is deployed with the Zoekt Helm chart or the GitLab Operator, so the choice usually follows your cluster tooling and your team's experience with each. Check the Zoekt documentation for the chart or Operator version that matches your GitLab release, and pin that version before writing any configuration. Done when the method and the pinned version are recorded in your change plan.

  3. Size storage from the Git footprint

    Measure the total Git size of the repositories you plan to index, then apply the sizing guidance in GitLab's Zoekt documentation. GitLab estimates initial indexing storage at roughly three times total repository Git size multiplied by the replica count, with steady-state use closer to half the Git size. Provision volumes for the first figure, since initial indexing is when storage peaks, and plan capacity for ongoing growth using the second. Ask your storage team how these volumes will be snapshotted and expanded. Done when the volume sizes and replica count are approved.

  4. Deploy the Zoekt indexer and web components

    Install the chart or Operator into a namespace or cluster you control, enabling the indexer and web components as the documentation describes. Apply the storage classes and volume sizes from the previous step, and place the Zoekt workloads where they can reach your GitLab instance over the network paths you have approved. Confirm that every pod reaches a running state and that the web component passes its health check before you continue. Done when the workloads are healthy and the volumes are bound.

  5. Connect Zoekt to your GitLab instance

    Register the Zoekt web endpoint in GitLab's administration settings so the instance knows where to send code search requests, and set the indexing scope for the groups and projects you want searchable. Make the change with an administrator account, and confirm the exact settings path in the documentation for your version. Check that GitLab shows the Zoekt connection as active and that the indexer can read the repositories in scope. Done when GitLab reports the connection as healthy.

  6. Run initial indexing and monitor progress

    Start the first full indexing run and monitor it until every in-scope project has been indexed. Watch the indexer logs and volume usage together, so you can catch failed projects and storage pressure early. If your scope is large, begin with a smaller group of projects to surface configuration problems before the full run. Done when indexing reports complete for all in-scope projects and volume usage has settled below the peak you provisioned for.

  7. Verify exact and regex queries

    Test search against a sample of repositories whose contents your team knows well. Run exact string queries and regular expressions whose results you can check by hand, and compare hit counts and file paths with what the repository holds. Repeat the test on a project with recent commits to confirm new changes are indexed. Also confirm that other search scopes, such as issues and merge requests, still depend on Elasticsearch or OpenSearch, which Zoekt does not replace. Done when every test query returns the expected results.

Why Elasticsearch or OpenSearch is still needed

Zoekt handles only code search, so Elasticsearch or OpenSearch remains a requirement for every other search scope. Exact match and regex queries over repository contents are the job Zoekt takes on. Searches for issues, merge requests, comments, commits and other non-code objects still rely on the advanced search backend. Teams that read the Zoekt feature as a replacement for their existing search cluster will find that the cluster stays in the architecture, and the budget, patching and on-call duties that come with it stay too.

The two search paths run side by side. Zoekt indexes repository contents through its own indexer and webserver components, deployed with the Zoekt Helm chart or the GitLab Operator. The advanced search backend is a separate Elasticsearch or OpenSearch cluster that GitLab indexes for the other scopes. Each path has its own storage, its own indexing job and its own failure modes, so a planning document should list both as distinct components with owners, network paths and monitoring. A query that spans code and issues will exercise both, so the reader should confirm how the GitLab user interface routes each search type before setting expectations with developers.

Before the cluster is planned, confirm the supported Elasticsearch and OpenSearch versions, the indexing order and the sizing rules for your user count in the GitLab documentation for advanced search, and the current Zoekt requirements in the GitLab Docs: Exact code search with Zoekt page. Ask your GitLab team to confirm whether the search backend will be a self-managed cluster or a managed service you operate, because that choice drives hosting, access control and upgrade planning. Record the decision in the architecture file so that the search dependency is visible to security reviewers and to the team that owns upgrades.

Security and operational considerations for code search

Zoekt indexes your source code, so it inherits the sensitivity of everything GitLab stores. The cards below cover the decisions that keep search results inside existing permissions, the indexers inside your trust boundary, and the index running in step with GitLab over time.

Permission checks on search results

Confirm that a user sees only the projects they can already read in GitLab. Search results must respect project visibility, group membership and private repositories at query time, not only at indexing time. Test this with a restricted test account against a private project and an internal project before you open search to the wider organization. Ask the vendor documentation how permission changes, such as a user removed from a group, reach the index.

Indexer placement in the trust boundary

Zoekt indexers read full copies of your repositories, so they belong inside the same network boundary as GitLab and its Gitaly storage. Decide whether indexer pods or VMs can reach only GitLab and the storage they need, and whether they can reach the internet at all. Review which service accounts and tokens the indexers hold, and keep them scoped to read access.

Encryption and backup of index data

The index is a derived copy of source code, so treat it with the same classification as the repositories. Confirm whether your storage class encrypts volumes at rest and who holds the keys. Decide whether the index is included in your backup routine or rebuilt after a restore, and record the rebuild time from a test so that recovery planning is based on measured data rather than assumptions.

Version alignment across components

Zoekt is deployed alongside GitLab through the Zoekt Helm chart or the GitLab Operator, and both must match the GitLab release you run. Plan Zoekt upgrades in the same change window as GitLab upgrades, and check the required upgrade stops before moving GitLab. Ask your support contact which Zoekt versions pair with each GitLab release you intend to run.

Monitoring of indexing health

Indexing can fall behind silently after a failed repository, a full disk or a stalled indexer, and search results then go stale without an error. Set alerts on indexer status, index age and free storage, and check that a newly pushed commit appears in search within the time your teams expect. Document who responds when the index stops updating and how a full reindex is started.

Questions teams ask before deploying Zoekt

What does exact code search with Zoekt cost in licensing?

Zoekt exact code search is a Premium and Ultimate feature, so you need at least a Premium subscription on top of your self-managed GitLab setup. The GitLab pricing page lists Premium at 29 US dollars per user per month billed annually, while Ultimate is custom priced and includes the security and compliance features that many regulated teams also need. Your license cost recurs per user, so the total depends on how many seats you buy and which tier your organization already runs. Ask your GitLab sales contact to confirm current seat counts and billing terms, and budget separately for the infrastructure that runs Zoekt, the search backend you still need for other scopes, and the people who operate them.

How long does a Zoekt deployment take?

No fixed duration applies to every environment, so the timeline depends on drivers you can measure. The biggest factors are how many repositories and how much Git history you index, because initial indexing storage is sized from total repository Git size and replica count. Other factors include whether you already run Kubernetes and the GitLab Operator, how many network and storage approvals your change process requires, and how many GitLab instances or Premium tiers need the feature. Ask any implementation partner for a written scope and timeline that lists these inputs explicitly.

What does the work need from our internal team?

Your team needs people who can run the GitLab installation, administer Kubernetes or the Operator, manage storage, and approve access for the search service. You also need a GitLab administrator who owns the license tier, the indexing schedule and upgrade planning, since Zoekt releases must stay aligned with the GitLab version you run. Security staff should review network paths between GitLab and the search components, and the team should agree on who responds when indexing falls behind. Expect to provide access to a test environment, sample repositories for validation and a change window for the production cutover.

Can our team deploy Zoekt without outside help?

Yes, if your team already operates GitLab and Kubernetes and has time to read the Zoekt documentation carefully. The harder part is usually not the first install but the ongoing work: sizing storage for initial indexing, validating search results after upgrades, and keeping the chart or Operator version compatible with GitLab. A partner can help when the team lacks Kubernetes or search operations experience, or when the rollout must fit a compliance change process. Whichever path you choose, agree on a written scope with named deliverables before work starts.

Is Elasticsearch still required if we use Zoekt?

Yes. Zoekt handles only code search, so Elasticsearch or OpenSearch remains necessary for other search scopes such as advanced search across issues, merge requests and other non-code content. Plan for both services side by side: Zoekt for exact match and regex code search, and the supported Elasticsearch or OpenSearch deployment for everything else. This means two sets of storage, sizing, backup and upgrade work. Confirm the exact supported versions for your GitLab release in the GitLab documentation before you commit to a design.

How much storage does Zoekt need for initial indexing?

GitLab sizes initial indexing storage at roughly three times the total repository Git size, multiplied by the replica count. Steady-state usage is closer to half the Git size. Measure your total repository size, decide how many replicas you need for availability and load, and multiply accordingly. Because the initial indexing peak is higher than steady state, provision storage for that peak rather than for day-to-day use. Ask your storage team to confirm that the volumes you plan can absorb the peak and expand later.

Which deployment method should we choose, the Helm chart or the Operator?

Choose the method that matches how your GitLab and Kubernetes platform is already managed. GitLab documents both the Zoekt Helm chart and the GitLab Operator as supported installs, so the decision usually follows your existing tooling, change control and upgrade process. Teams that manage GitLab through Helm values often prefer the chart, while teams that rely on Operator-driven lifecycle management often prefer the Operator. Whichever you select, confirm version compatibility with your GitLab release and document the upgrade path before the first deployment.

How DeployOpen scopes and delivers Zoekt deployments

A Zoekt deployment touches licensing, install path, storage and ongoing upgrades, so each step is agreed in writing before work starts. The cards below follow the order we use: fix the scope, plan the tier and install method, size storage from the Git footprint, deploy and verify, then decide how support continues.

Fixed scope agreed in writing

Most engagements are fixed-scope, so the repositories, groups, GitLab version, tier and deliverables are written down before work starts. For Zoekt, the scope should state which projects are indexed, whether Elasticsearch or OpenSearch remains in place for other search scopes, and what counts as a finished deployment. Ask for the written scope to list every item you expect to receive, including verification evidence.

Tier and install path planning

Exact code search with Zoekt requires Premium or Ultimate, so the first decision is whether your current edition meets that bar. The second is the install path: the Zoekt Helm chart for Kubernetes-based GitLab, or the GitLab Operator. We check the chosen path against your existing GitLab deployment method before any change is made.

Storage sized from Git footprint

Initial indexing storage is sized from your total repository Git size and the replica count, so the Git footprint must be measured before anything is provisioned. Confirm with GitLab how the replica count maps to your topology, and plan extra room for the first full index build. Steady-state storage is expected to be lower than the initial build, but the figure should be confirmed against your own repositories.

Deployment and verification in your infrastructure

The Zoekt components are deployed inside your cloud accounts, data centers or air-gapped network, with no search traffic leaving your boundary. Verification covers indexing completion for a sample of projects, exact-match and regex queries returning expected results, and access checks confirming that users only see code they are allowed to read. Keep the test queries and results as evidence for change records.

Elasticsearch scope kept separate

Zoekt covers code search only. Issues, merge requests, comments and other advanced search scopes still depend on Elasticsearch or OpenSearch, so that cluster stays in the design. We document which search features run on which backend so operators do not assume Zoekt replaces the full search stack. Confirm the supported versions for that cluster in the GitLab documentation before you size it.

Retainer support for upgrades

GitLab releases move quickly and require upgrade stops, so the Zoekt components need to move with the GitLab version. Optional retainer support covers planning each upgrade, checking chart or Operator compatibility, re-running verification and updating the runbook. Ask for the retainer scope in writing, including which GitLab versions and which environments are covered.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.