◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…
Articles/Dev Tools
⟐ Dev Tools/2026-05-01Intermediate

Sharpening Gemini CLI and Code Assist Context with .geminiignore — A

Use .geminiignore to clean up the context window for Gemini CLI and Code Assist, improving answer quality and cutting token usage at the same time.

gemini-cli8gemini-code-assistgeminiignorecontext-window3developer-tools5

The first wall most people hit with Gemini CLI or Code Assist is irrelevant files leaking into the context and making answers vague. I ran into this myself the day I added Code Assist to a monorepo at work — within minutes it was happily reading every type definition in node_modules and burning tokens for nothing useful.

The official answer to this is .geminiignore. It uses the same syntax as .gitignore, but the purpose is different: not "don't commit," but "don't let Gemini see this." This guide walks through how to use it well, with the rough edges I hit in real projects.

What .geminiignore Actually Does

.geminiignore is a plain text file you place at the root of your repository. Both Gemini CLI and Code Assist consult it when assembling the context they send to the model, and they skip anything that matches. The syntax is .gitignore-compatible: line-based glob patterns, ! for un-ignoring, # for comments.

It is easy to confuse with .gitignore, but they answer different questions.

  • .gitignore — should this be committed?
  • .geminiignore — should the AI read this?

A built dist/ folder usually wants to live in .gitignore but not be visible to Code Assist. Test snapshots are the opposite: often excluded from Git but valuable as context. The two files solve different problems, and trying to merge them eventually breaks somewhere.

One thing the official docs do not call out: in my testing, .geminiignore works most reliably when there is exactly one file, sitting at the project root. Files placed in subdirectories were either ignored outright or behaved inconsistently across tools.

Why Cleaning Up Context Improves Answer Quality

Gemini 3 models support 1M–2M token context windows, but answer quality consistently degrades as input grows. This is the well-known "Lost in the Middle" effect — the model attends less to information buried in the middle of a long input.

Three reasons to take .geminiignore seriously:

  • Better answers. Removing noise lets the model focus on the code that actually matters.
  • Lower cost. Fewer tokens read means less spend on metered APIs and more headroom inside monthly quotas.
  • Faster responses. Shorter inputs are noticeably faster to process, especially with the Flash family.

In my own project, Code Assist's Agent Mode was loading package-lock.json on every request, eating roughly 300K tokens by itself. Adding it to .geminiignore dropped the same task to about a tenth of the tokens, and that month's bill came in visibly lower.

A Solid Baseline .geminiignore

Here is a starter file I have settled on after using it across several projects. It tends not to break anything regardless of stack.

# .geminiignore — Generic baseline
 
# Dependencies
node_modules/
.pnpm-store/
vendor/
.venv/
__pycache__/
 
# Build artifacts
dist/
build/
.next/
out/
target/
*.min.js
*.bundle.js
 
# Lock files (huge, no value as context)
package-lock.json
pnpm-lock.yaml
yarn.lock
poetry.lock
Cargo.lock
 
# IDE / OS
.idea/
.vscode/settings.json
.DS_Store
 
# Secrets (most important)
.env
.env.*
!.env.example
*.pem
*.key
secrets/
 
# Large assets
*.mp4
*.zip
*.tar.gz
public/uploads/

Treat the secrets section as the highest priority. If .env makes its way into Gemini's context, your API keys can show up in generated code or answers. Even if .gitignore already covers them, listing them again in .geminiignore is the right kind of belt-and-suspenders.

Monorepo Patterns

In a recent monorepo I worked on, having both apps/web and apps/admin open meant noise from the other app constantly bled into Code Assist's answers. A .geminiignore like the one below lets you switch focus quickly:

# .geminiignore — Monorepo
 
# Shared exclusions
node_modules/
dist/
.turbo/
.next/
 
# Toggle: comment out to focus on admin only
# apps/web/
 
# packages/ui tests are gold for context — un-ignore them
packages/ui/dist/
!packages/ui/src/__tests__/

The trick here is leaning on ! to selectively bring things back. You can ignore packages/ui/dist/ while still letting __tests__/ through, because tests are some of the best material the model has for learning how an API is meant to be called. I almost never exclude test directories.

Switching .geminiignore per branch is also worth knowing about. On feature/admin-refactor, ignore apps/web/. On feature/web-redesign, do the opposite. The model stays anchored to whatever you are actually working on.

Measuring the Impact

It's easy to talk yourself into believing .geminiignore is helping. Numbers are better. The Gemini API exposes countTokens, which returns the exact token count a payload would use. A small script makes the comparison concrete.

# context_token_check.py
# Compare token usage before and after editing .geminiignore
import os
import pathlib
import fnmatch
from google import genai
 
# Load patterns from .geminiignore
def load_ignore_patterns(root: pathlib.Path) -> list[str]:
    ignore_file = root / ".geminiignore"
    if not ignore_file.exists():
        return []
    return [
        line.strip()
        for line in ignore_file.read_text().splitlines()
        if line.strip() and not line.startswith("#")
    ]
 
def is_ignored(path: pathlib.Path, patterns: list[str]) -> bool:
    rel = str(path)
    for pat in patterns:
        if fnmatch.fnmatch(rel, pat) or rel.startswith(pat.rstrip("/")):
            return True
    return False
 
def collect_context(root: pathlib.Path, patterns: list[str]) -> str:
    chunks = []
    for path in root.rglob("*"):
        if path.is_file() and not is_ignored(path.relative_to(root), patterns):
            try:
                chunks.append(path.read_text(errors="ignore"))
            except Exception:
                continue
    return "\n".join(chunks)
 
if __name__ == "__main__":
    client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
    root = pathlib.Path(".")
 
    patterns = load_ignore_patterns(root)
    context = collect_context(root, patterns)
 
    # countTokens returns the actual billable token count
    result = client.models.count_tokens(
        model="gemini-2.5-flash",
        contents=context,
    )
    print(f"Total tokens: {result.total_tokens:,}")
    print(f"Patterns active: {len(patterns)}")

Expected output looks like:

Total tokens: 38,420
Patterns active: 14

Run it before and after editing .geminiignore and you can see which patterns are actually pulling their weight. In one project, adding a single line for package-lock.json took the count from 300K tokens down to 40K.

Common Mistakes I've Made

A few things have tripped me up enough times that they are worth flagging.

The first is file location. .geminiignore belongs at the project root, next to .git. Putting it in a subdirectory is sometimes silently ignored — there is no warning when the file is in the wrong place, so this is the first thing to check when patterns "aren't working."

The second is editor reload. Code Assist's VS Code extension reads .geminiignore on startup, so changes only take effect after a restart. Gemini CLI picks up changes on its next launch.

The third is ! ordering. Like .gitignore, later patterns win, so un-ignoring (!pattern) must come after the ignore line, not before it. Reverse the order and your un-ignore quietly does nothing.

How It Fits with Other Gemini Config Files

The Gemini ecosystem has a handful of similarly-named files, and it helps to keep them straight.

  • .geminiignore — what to exclude from context
  • gemini.md / GEMINI.md — instructions, conventions, project background to pass to the model
  • .gemini/config.yaml — Gemini CLI behavior (model, output format, etc.)

These work independently. .geminiignore controls exclusion, gemini.md provides direction, and config.yaml shapes behavior. We covered the instruction file in detail in the GEMINI.md setup guide — pairing them roughly doubles the value of either.

If the CLI side itself still feels new, the Gemini CLI complete guide and the Code Assist Agent Mode walkthrough make a good companion read. .geminiignore clicks more once the surrounding tooling is familiar.

Start with One Line

If you take one thing from this guide, it's this: add a single line to .geminiignore today and see how it feels. Just node_modules/ and package-lock.json are usually enough to noticeably shift Code Assist's responsiveness and answer quality.

A safe order to grow the file: secrets first (.env*), then large files (lock files, build output), then noisy dependency directories (node_modules/, vendor/). You don't need a perfect file from day one — start small, watch your token counts, and iterate.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⟐ Dev Tools2026-10-17
Hung Jobs Fail Quietly — Wrapping a Scheduled Gemini Call With a Timeout, an Empty-Output Check, and a Lock
An outer shell script that protects a cron-driven `gemini -p` call from three quiet failures: hanging on a response, exiting 0 with empty output, and overlapping with the previous run. Includes exit codes and timings measured with stand-in commands, and how far `timeout` reaches into child processes.
⟐ Dev Tools2026-10-14
Stop Re-Reading Every Crash Report: Grep a Known-Bug Table First and Keep Only an Index in GEMINI.md
A routine for investigating app crash reports without making the model read every past bug in full: a one-line-per-bug lookup table, what belongs in GEMINI.md, and a grep helper you can paste in.
⟐ Dev Tools2026-09-29
Gemini CLI Kept Saying 'API key not valid' After I Gave It a New Key — It Was Reading an Old One From a Third Place
I switched Gemini CLI from Google login to a paid API key, and the 400 'API key not valid' error would not go away. The key can come from four places — the shell, a project .env, a home .env, and settings.json — and a short script that lights them up in order narrows the cause to one.