# SDK v2 migration guide (/docs/migration/v2)

<!-- agent-signals: reading_time_min: 3 · est_tokens: 1662 · updated: 2026-07-30 -->
Related: [V2 build system migration](/docs/migration/template-v2.md), [E2B_ACCESS_TOKEN deprecation](/docs/migration/access-token-deprecation.md), [V1 build system deprecation](/docs/migration/v1-build-deprecation.md), [Custom domain](/docs/network/custom-domain.md)

This guide helps you migrate from E2B SDK v1 to v2, covering all breaking changes and new patterns.

## Table of contents [#table-of-contents]

SDK v2 introduces several important changes:

* [**New creation pattern in Python Synchronous SDK**](#1-sandbox-creation-in-synchronous-python-sdk)
* [**Secure by default**](#2-secure-communication-by-default)
* [**Updated file operations in Python SDK**](#3-file-writing-in-python-sdk)
* [**Updated list method**](#4-listing-sandboxes)

## Breaking changes [#breaking-changes]

### 1. Sandbox creation in synchronous Python SDK [#1-sandbox-creation-in-synchronous-python-sdk]

In v2, the synchronous Python SDK uses a class method `create()` instead of the constructor `Sandbox()`.

<CodeGroup>
  <CodeBlockTabs defaultValue="Python" groupId="python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="Python">
      ```python  
      from e2b_code_interpreter import Sandbox

      sandbox = Sandbox.create()
      sandbox = Sandbox.create(template="base")
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

In the v1, you would instantiate directly:

<CodeGroup>
  <CodeBlockTabs defaultValue="Python" groupId="python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="Python">
      ```python  
      from e2b_code_interpreter import Sandbox

      sandbox = Sandbox()
      sandbox = Sandbox(template="base")
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

### 2. Secure communication by default [#2-secure-communication-by-default]

Sandboxes are now **secure by default**. This means you can't access the sandbox controller directly through its URL without an authentication header.
The SDK automatically handles the authentication header for you.

For custom templates created before envd `v0.2.0`, you need to rebuild them to enable secure communication.
Otherwise, you will receive error messages when creating sandboxes. You can check the template envd version using the `e2b template list` command or view the templates list in the dashboard.

You can temporarily disable secure communication by setting `secure` to `false` during sandbox creation, but this is not recommended for production environments.

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```js  
      import { Sandbox } from '@e2b/code-interpreter'

      const sandbox = await Sandbox.create({ secure: false }) // Explicitly disable
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```python  
      from e2b_code_interpreter import Sandbox

      sandbox = Sandbox.create(secure=False)  # Explicitly disable
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

Check more details in the [secured access documentation](/docs/sandbox/secured-access).

### 3. File writing in Python SDK [#3-file-writing-in-python-sdk]

The file writing API in Python has been made more consistent.

In v2, use `sandbox.files.write()` for single files and `sandbox.files.write_files()` for multiple files:

<CodeGroup>
  <CodeBlockTabs defaultValue="v2" groupId="v2">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="v2">
        v2
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="v2">
      ```python  
      from e2b_code_interpreter import Sandbox

      sandbox = Sandbox.create()

      # Write single file
      info = sandbox.files.write("/tmp/file.txt", "content")

      # Write multiple files
      infos = sandbox.files.write_files([
          {"path": "/tmp/file1.txt", "data": "content1"},
          {"path": "/tmp/file2.txt", "data": "content2"}
      ])
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

In v1, the same `write()` method was overloaded for both single and multiple files:

<CodeGroup>
  <CodeBlockTabs defaultValue="v1" groupId="v1">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="v1">
        v1
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="v1">
      ```python  
      from e2b_code_interpreter import Sandbox

      sandbox = Sandbox.create()

      # Write single file
      info = sandbox.write(path="/tmp/file.txt", data="content")

      # Write multiple files
      infos = sandbox.write([
          {"path": "/tmp/file1.txt", "data": "content1"},
          {"path": "/tmp/file2.txt", "data": "content2"}
      ])
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

### 4. Listing sandboxes [#4-listing-sandboxes]

The method for listing sandboxes has been updated to use pagination.

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```js  
      import { Sandbox, SandboxInfo } from '@e2b/code-interpreter'

      // Get paginator
      const paginator = Sandbox.list()

      // Iterate through all sandboxes
      for (const sandbox of await paginator.nextItems()) {
          console.log(sandbox.sandboxId)
      }

      // Iterate through all sandboxes
      const allSandboxes: SandboxInfo[] = []
      while (paginator.hasNext) {
          const items = await paginator.nextItems()
          allSandboxes.push(...items)
      }

      // With query
      const queryPaginator = Sandbox.list({query: {metadata: {key: "value"}}})
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```python  
      from e2b_code_interpreter import Sandbox, SandboxQuery

      # Get paginator
      paginator = Sandbox.list()

      # Iterate through all sandboxes
      while paginator.has_next:
          sandboxes = paginator.next_items()
          print(sandboxes)

      # With query
      paginator = Sandbox.list(query=SandboxQuery(metadata={"key": "value"}))
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>
