> ## Documentation Index
> Fetch the complete documentation index at: https://docs.browserbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Use secrets in Functions

> Attach secrets to a Browserbase Function and read them at runtime.

A Function can read only the secrets that you attach to it. When an invocation starts, Browserbase loads the attached values into `context.secrets`.

Before you begin, [create a secret](/platform/secrets/getting-started#create-a-secret) and create a Functions project with the [Functions quickstart](/platform/functions/quickstart#create-a-functions-project). The SDK examples use `@browserbasehq/sdk` for Node.js and `browserbase` for Python.

## Attach and use a secret

<Steps>
  <Step title="Read the secret in the handler">
    Read the value from `context.secrets` with the name that you chose when you created the secret:

    ```typescript Node.js theme={null}
    import { defineFn } from "@browserbasehq/sdk-functions";

    defineFn("call-service", async (context) => {
      const secrets = context.secrets as Record<string, string>;
      const serviceToken = secrets.SERVICE_TOKEN;

      if (!serviceToken) {
        throw new Error("Attach SERVICE_TOKEN before you invoke this Function");
      }

      const response = await fetch("https://api.example.com/data", {
        headers: {
          Authorization: `Bearer ${serviceToken}`,
        },
      });

      return { status: response.status };
    });
    ```

    Function secrets are not environment variables. Read attached secrets from `context.secrets`, not `process.env`.
  </Step>

  <Step title="Publish the Function">
    Publish the entrypoint:

    ```bash theme={null}
    browse functions publish index.ts
    ```

    The command prints the Function ID. Save it for the next step.
  </Step>

  <Step title="Attach the secret">
    Pass the Function ID and secret ID:

    <Tabs>
      <Tab title="Browse CLI">
        ```bash theme={null}
        browse functions secrets attach <function-id> <secret-id>
        browse functions secrets list <function-id>
        ```
      </Tab>

      <Tab title="Node.js">
        ```typescript Node.js theme={null}
        import { Browserbase } from "@browserbasehq/sdk";

        const bb = new Browserbase({
          apiKey: process.env.BROWSERBASE_API_KEY!,
        });

        const functionId = "<function-id>";
        const secretId = "<secret-id>";

        await bb.functions.secrets.attach(functionId, { secretId });

        const attachments = await bb.functions.secrets.list(functionId);
        console.log(attachments.data);
        ```
      </Tab>

      <Tab title="Python">
        ```python Python theme={null}
        import os
        from browserbase import Browserbase

        bb = Browserbase(api_key=os.environ["BROWSERBASE_API_KEY"])

        function_id = "<function-id>"
        secret_id = "<secret-id>"

        bb.functions.secrets.attach(function_id, secret_id=secret_id)

        attachments = bb.functions.secrets.list(function_id)
        print(attachments.data)
        ```
      </Tab>
    </Tabs>

    The Function and secret must belong to the same Browserbase project.

    The list contains metadata only. It does not contain secret values.
  </Step>

  <Step title="Invoke the Function">
    Invoke the deployed Function:

    ```bash theme={null}
    browse functions invoke <function-id>
    ```

    Browserbase loads the attached values when the invocation starts. The handler reads them from `context.secrets`.
  </Step>
</Steps>

<Accordion title="Test during local development">
  Function attachments apply only to deployed invocations. The local development server does not load them.

  Use a local environment variable as a development fallback:

  ```typescript Node.js theme={null}
  const attachedSecrets = context.secrets as
    | Record<string, string>
    | undefined;
  const serviceToken =
    attachedSecrets?.SERVICE_TOKEN ?? process.env.SERVICE_TOKEN;
  ```

  Don't commit local secret values or `.env` files.
</Accordion>

## Update an attached secret

Update the secret by ID:

```bash theme={null}
browse cloud secrets update <secret-id>
```

The update keeps the same secret ID and Function attachments. New invocations use the new value.

## Detach a secret

Remove the Function's access without deleting the secret:

<Tabs>
  <Tab title="Browse CLI">
    ```bash theme={null}
    browse functions secrets detach <function-id> <secret-id>
    browse functions secrets list <function-id>
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript Node.js theme={null}
    import { Browserbase } from "@browserbasehq/sdk";

    const bb = new Browserbase({
      apiKey: process.env.BROWSERBASE_API_KEY!,
    });

    const functionId = "<function-id>";
    const secretId = "<secret-id>";

    await bb.functions.secrets.detach(functionId, secretId);

    const attachments = await bb.functions.secrets.list(functionId);
    console.log(attachments.data);
    ```
  </Tab>

  <Tab title="Python">
    ```python Python theme={null}
    import os
    from browserbase import Browserbase

    bb = Browserbase(api_key=os.environ["BROWSERBASE_API_KEY"])

    function_id = "<function-id>"
    secret_id = "<secret-id>"

    bb.functions.secrets.detach(secret_id=secret_id, id=function_id)

    attachments = bb.functions.secrets.list(function_id)
    print(attachments.data)
    ```
  </Tab>
</Tabs>

Later invocations no longer receive the detached secret.

## Troubleshooting

| Problem | Check |
| - | - |
| Attach returns `404` | Confirm that the Function and secret IDs belong to the API key's project. |
| `context.secrets` does not contain the name | List the Function attachments, then compare the secret name with the code. |

## Next steps

<CardGroup cols={2}>
  <Card title="Manage secrets" icon="key" href="/platform/secrets/getting-started">
    Create, inspect, update, and delete secrets.
  </Card>

  <Card title="Invoke a Function" icon="terminal" href="/platform/functions/invoke">
    Pass parameters and retrieve asynchronous results.
  </Card>
</CardGroup>
