Skip to content

Gemini's Code Execution Tool: How It Runs and Returns Results Inline

9 min read · updated August 11, 2026

Code execution is a server-side tool: the model writes Python, Google runs it in a sandbox, the model reads the output, and all of that happens inside one generateContent call. Your client never executes anything, and the transcript of what ran comes back as ordinary parts in the response.

Declaring the tool

Unlike a function declaration, there is nothing to specify. You enable the built-in tool with an empty object, documented in Google’s code execution guide:

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tools": [{"codeExecution": {}}],
    "contents": [{"role": "user", "parts": [{
      "text": "What is the sum of the first 50 prime numbers? Compute it, do not estimate."
    }]}]
  }'

The field is codeExecution in REST’s camelCase and code_execution in the proto and in some SDK surfaces. Whether the tool is used at all is the model’s decision, exactly like a function call: the presence of the declaration makes it available, not mandatory.

The two new response parts

A Part in Gemini is a union — it can hold text, inlineData, functionCall, functionResponse, and for this tool two more. A response that used code execution contains them interleaved with the prose, in the order they happened:

{
  "candidates": [{
    "content": {
      "role": "model",
      "parts": [
        { "text": "I'll compute this directly." },
        { "executableCode": {
            "language": "PYTHON",
            "code": "from sympy import prime\ntotal = sum(prime(n) for n in range(1, 51))\nprint(total)\n"
        }},
        { "codeExecutionResult": {
            "outcome": "OUTCOME_OK",
            "output": "5117\n"
        }},
        { "text": "The sum of the first 50 primes is 5117." }
      ]
    },
    "finishReason": "STOP"
  }]
}

executableCode

Two fields. language is an enum whose only currently documented value is PYTHON (with LANGUAGE_UNSPECIFIED as the zero value). code is the source the model wrote, verbatim, before it ran. This is the auditable artefact: if the answer is wrong, the code is where the mistake is visible.

codeExecutionResult

outcome is an enum, and the documented members are the ones you must branch on:

  • OUTCOME_UNSPECIFIED — the zero value; treat as unknown.
  • OUTCOME_OK — the code ran to completion.
  • OUTCOME_FAILED — it raised. output carries the traceback, and the model usually reads it and writes a corrected version in a following executableCode part.
  • OUTCOME_DEADLINE_EXCEEDED — it ran too long and was killed.

output is whatever the process wrote to stdout and stderr, truncated if very large. Nothing else crosses back: the model sees exactly what was printed, so code that computes a value without printing it produces an OUTCOME_OK with an empty output and a model that then has nothing to report.

The loop happens server-side

This is the structural difference from ordinary function calling and the reason to prefer it where it fits. With a declared function, the model emits a functionCall, the call returns to you, you execute it, and you send a functionResponse back — at least two round trips over the network and a piece of orchestration you own.

With code execution the write-run-read cycle happens inside Google’s infrastructure. A single request can contain several executableCode / codeExecutionResult pairs where the model debugged its own script, and you receive the whole transcript at once. There is a documented ceiling on how many times it will iterate within a request, after which it stops and answers with what it has.

Because the iteration is invisible until the response arrives, a request using code execution has a much wider latency distribution than a plain generation. If you have a timeout tuned for text generation, it will fire on the occasional request where the model writes and rewrites a script three times.

Streaming changes what the wait feels like but not what happens. With streamGenerateContent the parts arrive in the order they are produced, so an executableCode part shows up as soon as the model has written the script and then nothing arrives while the code actually runs. If you are rendering the stream, that gap is a place to show the code and a running indicator rather than a stalled cursor — and it is worth handling, because a script that takes several seconds looks identical to a dead connection otherwise.

Code execution also composes with ordinary function declarations in the same request. Declare both and the model can fetch data through your function and then compute over it in the sandbox, which is the combination that makes the no-network restriction survivable. The parts come back interleaved: a functionCall you must answer, then on the follow-up request the executableCode and codeExecutionResult pair that used your data. If the model needs several of your functions at once, the same turn can carry multiple function calls alongside the code it wrote.

What the sandbox is

The environment is Python with a fixed set of scientific libraries available — NumPy, SymPy, pandas and Matplotlib among them — and no network access. You cannot install packages, and the model cannot reach an API, fetch a URL or read your filesystem. That isolation is the security property that makes the tool safe to enable on untrusted input, and it is also its main limitation.

Two capabilities are worth knowing about beyond arithmetic. Files uploaded through the File API can be made available to the execution environment for the model to load with pandas, which turns “analyse this CSV” into a real operation rather than a reading-comprehension exercise. And Matplotlib output comes back as an image part, so a request can return a chart the model drew from data it computed.

The library list, the per-execution time limit, the file size limits and the maximum number of iterations per request are all documented per model and have changed as the feature matured. Read them from the code execution guide for the model id you are calling.

What it costs you

There is no separate meter for the sandbox. The cost shows up as tokens: the code the model writes is output tokens, and the execution result is fed back into the model as input tokens for the next internal step. A request that iterates three times therefore bills considerably more than the length of the final answer suggests.

Read usageMetadata on the response for the actual figures rather than estimating from the visible text. The intermediate steps are all in there, and on a debugging-heavy request they can dominate.

When to reach for it

  • Exact arithmetic. A language model predicting the digits of a large multiplication is guessing; the same model writing print(a * b) is not. Anything where the answer must be correct rather than plausible belongs here.
  • Data manipulation over an attached file. Sorting, grouping, filtering and summing a CSV are operations pandas does exactly and a model approximates.
  • Anything with a checkable intermediate. Date arithmetic, unit conversion, parsing, regex validation — tasks where the model can verify its own work by running it.
  • Not for calling your systems. No network means no database, no internal API, no webhook. That is what function calling is for, and the two can be declared on the same request.