-   [](https://platform.exaloop.io/)
-   Get started
-   Exaloop CLI

# Exaloop CLI

The `exaloop` CLI builds Codon projects, runs their tests, and packages applications for deployment. It accepts Codon compiler commands and adds project configuration, SDK selection, profiling, and optimization. Its Python environment is bundled with the distribution; native applications do not require that environment to run.

For a first working project, follow the [quickstart](https://platform.exaloop.io/start/quickstart/). Use this page to look up the [compiler commands](https://platform.exaloop.io/start/cli/#codon-compatibility), [SDK registration](https://platform.exaloop.io/start/cli/#register-sdks), [project configuration](https://platform.exaloop.io/start/cli/#projects), [server builds](https://platform.exaloop.io/start/cli/#enterprise-builds), [Python extensions](https://platform.exaloop.io/start/cli/#python-extensions), [SDK tools](https://platform.exaloop.io/start/cli/#sdk-tools), and [testing and packaging](https://platform.exaloop.io/start/cli/#diagnose-test-package).

## Install

The [installation guide](https://platform.exaloop.io/start/distribution/) covers the tarball supplied by Exaloop. Once installed, the CLI and its SDK registrations are ready to use:

```sh title="Terminal"
exaloop --help
exaloop plugin list
```

## Codon Compatibility

Replace `codon` with `exaloop` for ordinary compiler commands:

```sh title="Terminal"
exaloop run -release program.codon argument1 argument2
exaloop build -release -o program program.codon
exaloop build -llvm program.codon
exaloop doc src/
exaloop jit
exaloop jupyter connection.json
```

Codon's `-plugin` and other compiler options remain available. Use `exaloop build --help` for compiler help, or `exaloop doctor` to see which compiler and SDKs will be used.

**Wrapper options precede the command.** Nothing following `run` is reparsed as an Exaloop option, so application arguments such as `--with` remain intact.

```sh title="Terminal"
exaloop --codon "$HOME/.codon/bin/codon" run program.codon
exaloop --with data --with kafka build -release processor.codon
exaloop --dry-run --with kafka build consumer.codon
```

`--verbose` prints the command before executing it. `--dry-run` prints the planned commands without creating files or invoking the compiler. Avoid passing credentials in command arguments, especially with verbose logging; use the application's environment or a protected runtime configuration instead.

## Register SDKs

Skip manual registration for SDKs supplied by your active all-SDK distribution. Register trusted, built or installed SDK directories containing `plugin.toml`:

```sh title="Terminal"
exaloop plugin add kafka --path /opt/exaloop/kafka
exaloop plugin add data --path /opt/exaloop/data
exaloop plugin list
exaloop plugin inspect kafka
exaloop plugin remove kafka
```

Registration gives an installed SDK a name; it does not download or copy it. Select that name with `--with` or add it to a project's `plugins` list. Use `--replace` to update a registration after moving an SDK. Removing a registration leaves its files intact.

The CLI checks selected SDKs before compilation, but they must still come from a trusted source and match your compiler. Run `exaloop doctor` after changing your toolchain.

## Application and Server Builds

```sh title="Terminal"
exaloop --kind postgres-udf build -release functions.codon -o dist/functions.so
exaloop --kind duckdb-extension build functions.codon -o dist/functions.duckdb_extension
exaloop --kind redis-module build commands.codon -o dist/commands.so
exaloop --kind mysql-udf build functions.codon -o dist/functions.so
exaloop --kind kafka-consumer build -release consumer.codon -o dist/consumer
```

| Kind | Automatically selected SDK | Output |
| --- | --- | --- |
| `native` | None | Codon's selected output format |
| `python-extension` | None | Importable CPython module; an installable wheel when packaged |
| `aws-lambda` | `aws-lambda` | Native handler; Linux container build context and SAM template when packaged |
| `duckdb-extension` | `duckdb` | DuckDB extension with native metadata |
| `postgres-udf` | `postgres` | Shared library, SQL, and extension control file |
| `mysql-udf` | `mysql` | Shared library, registration and removal SQL |
| `redis-module` | `redis` | Redis-loadable module |
| `kafka-producer` | `kafka` | Native executable |
| `kafka-consumer` | `kafka` | Native executable |
| `kafka-processor` | `kafka` | Native executable |

Server builds default to release mode and Python numerics. They accept `-debug`, `-release`, `-numerics=py|c`, `-o`, and repeated `-plugin` arguments. Native and Kafka builds keep Codon's defaults.

A successful server build produces a library, not a running service. Follow the database's guide to install the library and register its functions; the build command does not change a server.

For [AWS Lambda](https://platform.exaloop.io/cloud/aws-lambda/), use a named `aws-lambda` target. `run event.json` invokes a compiled handler locally; `package` requires a matching Linux environment and bundles its runtime dependencies automatically.

## Python Extensions

Exaloop compiles and links Codon modules for Python without a `setup.py`, Python headers, or setuptools in the destination environment. Start with an exported, typed `add(left: int, right: int) -> int` function:

```sh title="Terminal"
exaloop init fastmath --kind python-extension --name fastmath
cd fastmath
python3 -m venv .venv
exaloop --target fastmath package --python .venv/bin/python
.venv/bin/python -m pip install packages/fastmath/*.whl
.venv/bin/python -c 'import fastmath; print(fastmath.add(20, 22))'
```

`package` builds the module, collects its non-system native runtime dependencies, rewrites their loader paths, and writes a wheel under `packages/NAME/`. Runtime bundling is automatic for Python extensions. Installing the wheel does not require Exaloop or Codon. Each package destination must be new; use `--output packages/fastmath-v2` when packaging another version.

For development, build only the importable module:

```sh title="Terminal"
exaloop --target fastmath build --python .venv/bin/python
PYTHONPATH=dist/fastmath .venv/bin/python -c 'import fastmath; print(fastmath.add(20, 22))'
```

Exaloop generates the interpreter's ABI filename, such as `fastmath.cpython-312-darwin.so`. For this kind, `output` and `build -o` specify an **output directory**, defaulting to `dist/NAME/` for a named target and `dist/` otherwise. Dotted modules such as `acme.fastmath` create matching namespace-package directories. A standalone build is also supported:

```sh title="Terminal"
exaloop --kind python-extension build fastmath.codon --python .venv/bin/python -o dist
```

Configure persistent module and wheel settings in the target:

```toml title="Configuration"
[targets.fastmath]
kind = "python-extension"
source = "fastmath.codon"
codon_args = ["-release"]

[targets.fastmath.options]
module = "fastmath"
distribution = "fastmath"
version = "0.1.0"
python = ".venv/bin/python"
```

`module` defaults to the source basename, `distribution` to its top-level module, and `version` to `0.1.0`. `python` defaults to Exaloop's own interpreter, which may be different from your application's Python. Both `build --python` and `package --python` override it. Build accepts `--module`, `-debug`, `-release`, `-numerics=py|c`, and repeated `-plugin` arguments. Project `plugins` and wrapper `--with` selections work as usual. Use `doctor` with the target selected to check the configured interpreter, linker, and Codon runtime.

Build separately for each GIL-enabled CPython version and architecture. Supported hosts are macOS and Linux with CPython 3.9 or newer. Wheels are platform-specific, not `abi3`, universal2, or manylinux wheels; the build host's OS/libc baseline and SDK requirements still apply. Codon source is compiled for a generic CPU on the host architecture. Native libraries loaded dynamically need an explicit `package --runtime-library PATH`; Python dependencies and application data are managed separately. Distribution license inventories are included when building with an Exaloop distribution; review redistribution requirements for custom toolchains and additional libraries. See [production deployment](https://platform.exaloop.io/production/#python-extensions).

## Projects

Create a starter project, without overwriting existing files:

```sh title="Terminal"
exaloop init events --kind kafka-consumer
exaloop --project events --target app build
exaloop --project events --target app run localhost:9092 readers events 1000
```

This creates a consumer project and runs it against the `events` topic until it has processed 1,000 records. Create the topic first and adapt the connection settings for your cluster. The [Kafka guide](https://platform.exaloop.io/streaming/kafka/) explains processing, commits, and recovery.

`init` supports every build kind in the table above. Use `--name` to choose the target and source name; server targets need lowercase identifiers such as `scoring_udf`.

Projects use `exaloop.toml`, discovered in the current directory or its ancestors:

```toml title="Configuration"
[targets.scoring]
kind = "postgres-udf"
source = "scoring.codon"
plugins = ["data"]
codon_args = ["-release"]

[targets.scoring.options]
schema = "analytics"
version = "0.1.0"

[targets.events]
kind = "kafka-consumer"
source = "events.codon"
codon_args = ["-release"]
```

Use `--project DIRECTORY_OR_FILE` to select a project, or `--no-project` to disable discovery. Targets are never selected implicitly. Relative project paths are resolved from the manifest's directory; named-target commands run there as well. Project plugin paths override user registrations.

Compiler selection is `--codon`, then project `toolchain.codon`, then `EXALOOP_CODON`, then `codon` on `PATH`. `--stdlib` overrides `toolchain.stdlib`; otherwise an inherited `CODON_PATH` remains intact. Always select a compiler, standard library, and runtime from the same distribution.

Target output defaults to `dist/NAME/NAME`, with the appropriate server suffix. Python extensions instead use the output-directory convention described above. Set `output` in the target to override it. For `build`, command-line `-o`, `-debug`/`-release`, and `-numerics` override their target defaults. Other Codon flags follow Codon's own combination rules. For a named-target `run`, arguments after `run` are application arguments; compiler flags belong in `codon_args`.

Host settings belong in the target's `options` table:

| Kind | Available settings |
| --- | --- |
| DuckDB | `platform`, `version` |
| PostgreSQL | `schema`, `version` |
| MySQL | `mysql_config` |
| Python extension | `module`, `python`, `distribution`, `version` |

These settings do not cross-compile code. In particular, DuckDB's `platform` sets extension metadata; it must describe the platform actually being built. PostgreSQL uses the matching host tooling recorded in its SDK.

## SDK Tools

Run the SDK's generators and builders through the same CLI:

```sh title="Terminal"
exaloop avrogen event.avsc event.codon
exaloop protoc -Ischemas --codon_out=generated schemas/event.proto
exaloop profdata -o merged.profdata capture.profraw
exaloop --with data --dry-run avrogen event.avsc event.codon
exaloop tool --list
exaloop --with data tool --list
```

Create Protobuf output directories before invoking `protoc`. The CLI locates the generator and standard schemas in the Data SDK for you.

| Command | Default SDK | Standalone tool |
| --- | --- | --- |
| `avrogen` | `data` | `bin/avrogen-codon` |
| `protoc` | `data` | Bundled `protoc`, with Codon plugin discovery |
| `protoc-gen-codon` | `data` | Raw binary Protobuf generator protocol |
| `profdata` | `ext` | `exaloop-profdata` |
| `duckdb-build` | `duckdb` | Complete DuckDB `build.py` interface |
| `postgres-build` | `postgres` | Complete PostgreSQL `build.py` interface |
| `mysql-build` | `mysql` | Complete MySQL `build.py` interface |
| `redis-build` | `redis` | Complete Redis `build.py` interface |

Use `--with NAME` to select another SDK alias. Arguments after the command belong to that tool, including `--help`. The direct database builders use `--mode release`; the higher-level `--kind KIND build` uses Codon's `-release`.

The generic dispatcher also runs tools included in a selected SDK or a tool specified by an explicit path:

```sh title="Terminal"
exaloop --with data tool avrogen-codon event.avsc event.codon
exaloop --with redis tool build.py --help
exaloop tool /absolute/path/to/native-tool --help
```

Tools run from the project directory when a project is selected, or from the current directory otherwise. Tool execution has the same permissions as the CLI; `--dry-run` shows the planned command without executing it.

## Diagnose, Test, Package

For function timings and memory measurements, see the [profiling guide](https://platform.exaloop.io/start/profiling/). `exaloop --profile run ...` enables capture; `--profile=memory` requests memory statistics without XRay.

```sh title="Terminal"
exaloop doctor
exaloop --target scoring doctor --json
exaloop doctor --optimization --optimizer-sdk /path/to/sdk/ext --json
exaloop --target scoring test
exaloop --target scoring package --output packages/scoring-v1
```

`doctor` checks your compiler and SDKs, including the host tools needed by a server target. Resolve its errors before building. For optimization, it also compiles and runs a small PGO check; the [PGO walkthrough](https://platform.exaloop.io/opt/) then takes you through optimizing your own program.

`test` first builds a named target, then runs its explicit `test` argument array without a shell. For example, set `test = ["python3", "tests/check.py"]` inside the target table. The command receives `EXALOOP_ARTIFACT` with the absolute output path, and arguments after `test --` are forwarded to it. Test commands are trusted project code; no database or Kafka service is started automatically.

`package` builds a target and collects its output, checksums, and deployment notes in a new directory. By default it includes **build artifacts only**, not their runtime libraries. Review generated SQL before deployment; PostgreSQL's unversioned SQL still refers to the local build path.

Python-extension targets are the exception: `package` produces an installable wheel and always bundles its native runtime dependencies, as described [above](https://platform.exaloop.io/start/cli/#python-extensions).

For runtime-only packaging, request it explicitly:

```sh title="Terminal"
exaloop --target events package --bundle-runtime --output packages/events-v1
```

This includes the native libraries needed by the application. The [runtime-package guide](https://platform.exaloop.io/start/distribution/#runtime-only-packages) explains target requirements and what you still need to supply. Packaging does not deploy the application or install database functions.

The [distribution workflow](https://platform.exaloop.io/start/distribution/) also supports verified release installation, rollback, and [project locks](https://platform.exaloop.io/start/distribution/#project-lock). Use a project lock when a team needs to build with the same distribution.

For installation or execution problems, see [troubleshooting](https://platform.exaloop.io/development/troubleshooting/).

Source: https://platform.exaloop.io/start/cli/
