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

# Deploy jobs

> Deploy batch jobs on Blaxel as serverless, autoscalable workloads using the CLI, GitHub integration, or Dockerfile-based deployments.

This guide assumes you have developed a job locally.

The [Blaxel SDK](../sdk-reference/introduction) allows you to connect to and orchestrate other resources (such as model APIs, tool servers, multi-agents) during development, and ensures telemetry, secure connections to third-party systems or private networks, smart global placement of workflows, and much more when jobs are deployed.

<Accordion title="Learn more about authentication on Blaxel">
  The Blaxel SDK requires two environment variables to authenticate:

  | Variable       | Description                |
  | -------------- | -------------------------- |
  | `BL_WORKSPACE` | Your Blaxel workspace name |
  | `BL_API_KEY`   | Your Blaxel API key        |

  You can create an API key from the [Blaxel console](https://app.blaxel.ai/profile/security). Your workspace name is visible in the URL when you log in to the console (e.g. `app.blaxel.ai/{workspace}`).

  Set them as environment variables or add them to a `.env` file at the root of your project:

  ```bash theme={null}
  export BL_WORKSPACE=my-workspace
  export BL_API_KEY=my-api-key
  ```

  When developing locally, you can also **log in to your workspace with Blaxel CLI** (as shown above). This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, authentication is handled automatically — no environment variables needed.
</Accordion>

## Deploy on production

You can deploy the job in order to make the entrypoint function (by default: `index.ts` / `server.py`) **callable on a global endpoint**. When deploying to Blaxel, you get a dedicated endpoint that enforces your [deployment policies](../Model-Governance/Policies).

Run the following command to build and deploy a local job on Blaxel:

```bash theme={null}
bl deploy
```

You can alternatively use `bl push` to build and push the job container image to the Blaxel registry without creating or updating the deployment. This is useful for preparing images in advance.

## Run a job

Each deployed job has an HTTP endpoint to trigger a batch execution. You can find this endpoint in the Blaxel console, on the detail page for your deployed job.

<Note>
  HTTP endpoints are only available for deployed jobs.
</Note>

You can invoke a job in multiple ways:

* using the Blaxel SDK, API, or language-native HTTP client (only for deployed jobs);
* using the Blaxel CLI;
* scheduling it to run periodically via a cron.

### **SDK**

Start batch job execution using the SDK:

<CodeGroup>
  ```tsx TypeScript theme={null}
  import { blJob } from "@blaxel/core";

  const JOB_NAME = "YOUR_JOB_NAME"; // ex : my-job (not the display name)

  async function execJob() {
    const job = blJob(JOB_NAME);
    let result = await job.run([{"name": "John"}, {"name": "Jane"}])
    console.log(result);
  }

  execJob().catch(console.error);
  ```

  ```python Python (asynchronous) theme={null}
  from blaxel.core.jobs import bl_job
  import asyncio

  async def exec_job():
      try:
        job = bl_job("YOUR_JOB_NAME");
        result = await job.arun([{"name": "John"}, {"name": "Jane"}])
        print(result)
      except Exception as e:
          print(f"Failed to execute job: {e}")

  asyncio.run(exec_job())
  ```

  ```python Python (synchronous) theme={null}
  from blaxel.core.jobs import bl_job

  def exec_job():
      try:
        job = bl_job("YOUR-JOB-NAME");
        result = job.run([{"name": "John"}, {"name": "Jane"}])
        print(result)
      except Exception as e:
          print(f"Failed to execute job: {e}")

  exec_job()
  ```
</CodeGroup>

### **API**

Start batch job execution by [calling the inference API for your deployed batch job](../api-reference/inference).

Here is an example using `curl`:

```http Execute a job theme={null}
curl -X POST "https://api.blaxel.ai/$(bl workspace --current)/jobs/{your-job-name}/executions" \
  -H "Content-Type: application/json" \
  -H "X-Blaxel-Workspace: $(bl workspace --current)" \
  -H "X-Blaxel-Authorization: Bearer $(bl token)" \
  -d '{"tasks":[{"name":"John"},{"name":"Jane"}]}'
```

Here is an example using a language-native HTTP client:

<CodeGroup>
  ```tsx TypeScript theme={null}
  async function execJob() {
    console.log("Executing job");
    const WORKSPACE = "YOUR_WORKSPACE_NAME"; // ex : my-workspace (not the display name)
    const JOB_NAME = "YOUR_JOB_NAME"; // ex : my-job (not the display name)
    const response = await fetch(`https://api.blaxel.ai/${WORKSPACE}/jobs/${JOB_NAME}/executions`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Blaxel-Authorization': `Bearer ${process.env.BL_API_KEY}`,
        'X-Blaxel-Workspace': WORKSPACE
      },
      body: JSON.stringify({
        tasks: [
          { "name": "John" },
          { "name": "Jane" }
        ]
      })
    });
    if(response.status !== 200) {
      console.error(`Failed to execute job : ${response.statusText}`);
      return;
    }
    const result = await response.json();
    console.log(result);
  }

  execJob().catch(console.error);
  ```

  ```python Python theme={null}
  import os
  import aiohttp
  import asyncio

  async def exec_job():
      workspace = "YOUR_WORKSPACE_NAME" # ex : my-workspace (not the display name)
      job_name = "YOUR_JOB_NAME" #  ex : my-job (not the display name)
      api_key = os.environ.get("BL_API_KEY")
      try:
          async with aiohttp.ClientSession() as session:
              print("Executing job")
              resp = await session.post(
                  f"https://api.blaxel.ai/{workspace}/jobs/{job_name}/executions",
                  json={
                      "tasks": [
                          { "name": "John" },
                          { "name": "Jane" }
                      ]
                  },
                  headers={
                      "Content-Type": "application/json",
                      "X-Blaxel-Authorization": f"Bearer {api_key}",
                      "X-Blaxel-Workspace": workspace
                  }
              )
              data = await resp.text()
              print(data)
      except Exception as e:
          print(f"Failed to execute job: {e}")

  asyncio.run(exec_job())
  ```
</CodeGroup>

### **CLI**

For deployed jobs, you can start a batch job execution by running:

```bash theme={null}
# Run a deployed job using Blaxel CLI with --data argument
bl run job <<JOB-NAME>> --data '{"tasks": [{"name": "John"}, {"name": "Jane"}]}'

# Run a deployed job using Blaxel CLI with --file argument
bl run job <<JOB-NAME>> --file batches/sample-batch.json
```

When running a job locally, only JSON file input is currently supported, and you must include the `--local` argument:

```bash theme={null}
# Run a job locally using Blaxel CLI with --local and --file argument
bl run job <<JOB-NAME>> --local --file batches/sample-batch.json
```

You can cancel a job execution from the Blaxel Console or via API.

### **Cron schedule**

Set a job on a cron schedule by adding the following to the `blaxel.toml` configuration file (read full reference on *blaxel.toml* down below):

```toml theme={null}
[[triggers]]
id = "cron-trigger"
type = "cron"

[triggers.configuration]
schedule = "0 * * * *"
```

### Retries

You can set a maximum number of **retries per task** in the job definition. Check out the reference for `blaxel.toml` configuration file down below.

### Metrics

The **Blaxel Console** > **Dashboard** displays detailed job metrics, including the number of active jobs, failures, and requests (both count and requests per second (RPS)) across all deployments.

<img src="https://mintcdn.com/blaxel/OV8J20a-e6sNRxmO/Jobs/Overview/job-metrics.webp?fit=max&auto=format&n=OV8J20a-e6sNRxmO&q=85&s=346c0304f2e4faad5af559d9d35c58b7" alt="image" width="1861" height="985" data-path="Jobs/Overview/job-metrics.webp" />

## Deploy with a Dockerfile

While Blaxel uses predefined, optimized container images to build and deploy your code, you can also deploy your workload using your own [Dockerfile](https://docs.docker.com/reference/dockerfile/).

<Card title="Deploy using Dockerfile" icon="folder-tree" href="/Jobs/Deploy-dockerfile-jobs">
  Deploy resources using a custom Dockerfile.
</Card>

## Deploy multiple jobs at once

Using a custom Dockerfile allows for [deploying multiple jobs from the same repository](/Jobs/Deploy-multiple-jobs) with shared dependencies.

<Card title="Deploy multiple resources with shared files" icon="folder-tree" href="/Jobs/Deploy-multiple-jobs">
  Deploy multiple jobs with shared context from a single repository.
</Card>

<Card title="Deploy multiple jobs from a single image" icon="image" href="/Jobs/Deploy-shared-image">
  Reuse a job image across multiple job definitions.
</Card>

## Template directory reference

### Overview

```text theme={null}
package.json            # Mandatory. This file is the standard package.json file, it defines the entrypoint of the project and dependencies.
blaxel.toml             # This file lists configurations dedicated to Blaxel to customize the deployment.
tsconfig.json           # This file is the standard tsconfig.json file, only needed if you use TypeScript.
src/
└── index.ts            # This file is the standard entrypoint of the project. It is where the core logic of the job is implemented.
└── steps               # This is an example of organization for your sub steps, feel free to change it.
```

### package.json

Here the most notable imports are the scripts. They are used for the `bl serve` and `bl deploy` commands.

```json theme={null}

{
  "name": "job-ts",
  "version": "1.0.0",
  "description": "Job using Blaxel Platform",
  "main": "src/index.ts",
  "keywords": [],
  "license": "MIT",
  "author": "Blaxel",
  "scripts": {
    "start": "tsx src/index.ts",
    "prod": "node dist/index.js",
    "build": "tsc"
  },
  "dependencies": {
    "@blaxel/core": "0.2.5",
    "@blaxel/telemetry": "0.2.5"
  },
  "devDependencies": {
    "@types/express": "^5.0.1",
    "@types/node": "^22.13.11",
    "tsx": "^4.19.3",
    "typescript": "^5.8.2"
  }
}
```

Depending on what you do, all of the `scripts` are not required. With TypeScript, all 4 of them are used.

* `start` : start the job locally through the TypeScript command, to avoid having to build the project when developing.
* `prod` : start the job remotely from the dist folder, the project needs to be have been built before.
* `build` : build the project. It is done automatically when deploying.

The remaining fields in package.json follow standard JavaScript/TypeScript project conventions. Feel free to add any dependencies you need, but keep in mind that devDependencies are only used during the build process and are removed afterwards.

### blaxel.toml

The deployment can be configured via the `blaxel.toml` file in your agent directory. This file is not mandatory; if the file is not found or a required option is not set, you will be prompted for the information during deployment.

```toml theme={null}

type = "job"
name = "my-job"
workspace = "my-workspace"

policies = ["na"]

[env]
DEFAULT_CITY = "San Francisco"

[runtime]
memory = 1024
maxConcurrentTasks = 10
timeout = 900
maxRetries=0

[[triggers]]
id = "cron-trigger"
type = "cron"

[triggers.configuration]
schedule = "0 * * * *"
tasks = [
  { p_id = "1234", arg2 = "foo" },
  { p_id = "5678", arg2 = "bar" }
]
```

* `name`, `workspace`, and `type` fields are optional and serve as default values. Any bl command run in the folder will use these defaults rather than prompting you for input.
* `policies` fields is also optional. It allow you to specify a Blaxel [policy](../Model-Governance/Policies) to customize the deployment. For example, deploy it only in a specific region of the world.
* `[env]` section defines environment variables that the job can access via the SDK. Note that these are NOT secrets.
* `[runtime]` section allows to override job execution parameters: maximum number of concurrent tasks, maximum number of retries for each task, timeout (in s), or memory (in MB) to allocate.
* `[tasks]` sections allows to specify
* `[[triggers]]` and `[triggers.configuration]` sections define ways to schedule job executions.
  * `type = "cron"` lets you create a cron schedule for the job to run periodically. The job will be executed without any argument by default. You can override this by passing:
    * `tasks = [{my_arg="my_value"}]` containing a list of task to execute at each occurrence of the cron (default value is one task, without arguments)

A private HTTP endpoint to launch job executions is always available by default, even if you don't define a trigger in this file. You can launch a job execution by sending a POST request with the correct job and workspace arguments to `https://api.blaxel.ai/v0/jobs/my-job/executions?workspace=my-workspace`.
