> ## Documentation Index
> Fetch the complete documentation index at: https://tbd-6fc993ce-hypeship-ia-how-it-works.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy an App

> Deploy your app to KERNEL, set environment variables, and pass secrets

Kernel's app deployment process is as simple as it is fast. There are no configuration files to manage or complex CI/CD pipelines.

Once you deploy an app on Kernel, you can schedule its actions on a job or run them from other contexts. You can even run actions multiple times in parallel.

## Deploy the app

### From local directory

Use our CLI from the root directory of your project:

```bash theme={null}
kernel deploy <entrypoint_file_name>
```

#### Notes

* The `entrypoint_file_name` is the file name where you [defined](/apps/develop) your app.
* Include a `.gitignore` file to exclude dependency folders like `node_modules` and `.venv`.

### From GitHub

You can deploy a Kernel app directly from a public or private GitHub repository using the Kernel CLI. No need to clone or manually push code.

```bash theme={null}
kernel deploy github \
  --url https://github.com/<owner>/<repo> \
  --ref <branch|tag|commit> \
  --entrypoint <path/to/entrypoint> \
  [--path <optional/subdir>] \
  [--github-token <token>] \
  [--env KEY=value ...] \
  [--env-file .env] \
  [--version latest] \
  [--force]
```

#### Notes

* **`--path` vs `--entrypoint`:** Use `--path` to specify a subdirectory within the repo (useful for monorepos), and `--entrypoint` for the path to your app's entry file relative to that directory (or repo root if no `--path` is specified).
* The CLI automatically downloads and extracts the GitHub source code and uploads your app for deployment.
* For private repositories, provide a `--github-token` or set the `GITHUB_TOKEN` environment variable.

## Environment variables

You can set environment variables for your app using the `--env` flag. For example:

<CodeGroup>
  ```bash Typescript/Javascript (inline) theme={null}
  kernel deploy my_app.ts --env MY_ENV_VAR=my_value # Can add multiple env vars delimited by space
  ```

  ```bash Typescript/Javascript (from file) theme={null}
  kernel deploy my_app.ts --env-file .env
  ```

  ```bash Python (inline) theme={null}
  kernel deploy my_app.py --env MY_ENV_VAR=my_value # Can add multiple env vars delimited by space
  ```

  ```bash Python (from file) theme={null}
  kernel deploy my_app.py --env-file .env
  ```
</CodeGroup>

### Reserved environment variables

Kernel injects a few environment variables into every deployment and its invocations. These names are **reserved** — if you set them via `--env` or `--env-file`, Kernel overrides your value, so setting them has no effect:

* `KERNEL_API_KEY` — a per-deployment API key Kernel mints at deploy time (see [Deployment API keys](/info/api-keys#deployment-api-keys)). The SDKs read it from the environment by default, so your app authenticates with this key automatically.
* `ENTRYPOINT_RELPATH` — set by the platform to locate your entrypoint.

#### Using a different key for your app's calls

You can't change `KERNEL_API_KEY` itself, but you can have your app authenticate with a different key — say a long-lived org- or project-scoped key that outlives any single deployment. Put it in a **non-reserved** variable and pass it to the client explicitly:

<CodeGroup>
  ```python Python theme={null}
  import os
  from kernel import Kernel

  # Use your own key from a non-reserved var instead of the injected deployment key.
  client = Kernel(api_key=os.environ["MY_KERNEL_API_KEY"])
  ```

  ```typescript TypeScript theme={null}
  import Kernel from '@onkernel/sdk';

  const client = new Kernel({ apiKey: process.env.MY_KERNEL_API_KEY });
  ```
</CodeGroup>

Now the API calls your app makes go out as your key. The deployment key stays in place for Kernel's own use — running the invocation and reporting its result — so your key only needs permissions for the calls you actually make.

## Secrets

Pass API keys and other secrets as [environment variables](#environment-variables) when you deploy, with `--env` or `--env-file`. Then read them in your app:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import Anthropic from "@anthropic-ai/sdk";
  import OpenAI from "openai";

  app.action('ai-action', async (ctx: KernelContext) => {
    // Access API keys from environment variables
    const anthropic = new Anthropic({
      apiKey: process.env.ANTHROPIC_API_KEY,
    });

    const openai = new OpenAI({
      apiKey: process.env.OPENAI_API_KEY,
    });

    // Use the clients...
  });
  ```

  ```python Python theme={null}
  import os
  from anthropic import Anthropic
  from openai import OpenAI

  @app.action("ai-action")
  async def ai_action(ctx: KernelContext):
      # Access API keys from environment variables
      anthropic = Anthropic(
          api_key=os.environ.get("ANTHROPIC_API_KEY"),
      )

      openai = OpenAI(
          api_key=os.environ.get("OPENAI_API_KEY"),
      )

      # Use the clients...
  ```
</CodeGroup>

### Per-invocation secrets

For use cases where different API keys are needed per invocation (such as platforms using end-user keys), pass the secrets at runtime using the [payload parameter](/apps/invoke#payload-parameter).

Use encryption standards in your app to protect sensitive data.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import OpenAI from "openai";

  app.action('ai-action', async (ctx: KernelContext, payload) => {
    // Decrypt the API key passed at runtime
    const apiKey = decrypt(payload.encryptedApiKey);

    const openai = new OpenAI({
      apiKey: apiKey,
    });

    // Use the client with the user's API key...
  });
  ```

  ```python Python theme={null}
  from openai import OpenAI

  @app.action("ai-action")
  async def ai_action(ctx: KernelContext, payload):
      # Decrypt the API key passed at runtime
      api_key = decrypt(payload["encryptedApiKey"])

      openai = OpenAI(
          api_key=api_key,
      )

      # Use the client with the user's API key...
  ```
</CodeGroup>

## Deployment notes

* **The dependency manifest (`package.json` for JS/TS, `pyproject.toml` for Python) must be present in the root directory of your project.**
* **For JS/TS apps, set `"type": "module"` in your `package.json`.**
* View deployment logs using: `kernel deploy logs <deployment_id> --follow`
* If you encounter a 500 error during deployment, verify that your entrypoint file name and extension are correct (e.g., `app.py` not `app` or `app.js`).
* Kernel assumes the root directory contains at least this file structure:

<CodeGroup>
  ```bash Typescript/Javascript theme={null}
  project-root/
    ├─ .gitignore # Exclude dependency folders like node_modules
    ├─ my_app.ts # Entrypoint file (can be located in a subdirectory, e.g. src/my_app.ts)
    ├─ package.json
    ├─ tsconfig.json # If using TypeScript
    └─ bun.lock | package-lock.json | pnpm-lock.yaml # One of these lockfiles
  ```

  ```bash Python theme={null}
  project-root/
    ├─ .gitignore # Exclude dependency folders like .venv
    ├─ my_app.py # Entrypoint file
    └─ pyproject.toml
  ```
</CodeGroup>

```bash theme={null}
# Successful deployment CLI output
SUCCESS  Compressed files
SUCCESS  Deployment successful
SUCCESS  App "my_app.ts" deployed with action(s): [my-action]
INFO  Invoke with: kernel invoke my-app my-action --payload '{...}'
SUCCESS  Total deployment time: 2.78s
```

Once deployed, you can [invoke](/apps/invoke) your app from anywhere.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.