Configuration¶
mlxcel is configured through a combination of environment variables (which affect all invocations) and command-line flags (which override environment variables for a specific run). This page documents the environment variables that control device selection and memory management, as well as the server-specific configuration options.
Table of Contents¶
- Environment Variables
- Device Selection
- Memory Management
- Server Configuration
- Networking and Authentication
- Generation Defaults
- Continuous Batching
- Speculative Decoding
- Chat Templates
Environment Variables¶
These variables are read at startup and apply to both the generate command and the serve command.
| Variable | Description | Default |
|---|---|---|
MLXCEL_DEVICE | Force the runtime device. Accepted values: gpu, metal, cpu. | Auto (GPU if available) |
MLXCEL_WIRED_LIMIT | GPU wired memory limit. See Memory Management for format details. | max GPU memory |
MLXCEL_MEMORY_LIMIT | Soft MLX allocator memory cap. Also feeds mlxcel inspect and --estimate-memory as the authoritative available-memory figure when nonzero. | Unset |
MLXCEL_HEADROOM_FACTOR | Runtime/activation headroom multiplier used by the unified memory estimator. Positive values <= 1.0 disable the headroom term; invalid or non-positive values warn and fall back to the default. | 1.20 |
MLXCEL_CACHE_DIR | Root for the default model store ($MLXCEL_CACHE_DIR/models/<owner>/<name>) and other mlxcel disk caches. | $HOME/.cache/mlxcel |
MLXCEL_MODELS_DIR | Override the model-store root directly. Repo-id downloads and lookups use $MLXCEL_MODELS_DIR/<owner>/<name> with no extra models/ component. | Unset |
MLXCEL_DEFAULT_ORG | Default HuggingFace owner for bare model names with no slash. | mlx-community |
MLXCEL_WEIGHT_MATERIALIZATION | eager reads and uploads a generation model's checkpoint tensors before Model loaded is reported, so the first token pays no weight I/O. lazy materializes each tensor on first use. | eager |
MLXCEL_EXTRA_CA_CERTS | PEM bundle (at most 1 MiB) of extra root or intermediate CAs trusted for model downloads and remote media fetches, on top of the operating system trust store. Needed behind a TLS-inspecting proxy whose root CA the system store lacks. | Unset |
CUDA_HOME | Path to the CUDA Toolkit installation directory (Linux only, build-time). | /usr/local/cuda |
MLX_CUDA_ARCHITECTURES | Target GPU SM version(s) for CUDA kernel compilation (Linux only, build-time). | Auto-detected via nvidia-smi |
LLAMA_ARG_MODEL | Default model path (used by mlxcel serve and mlxcel-server). | None |
LLAMA_ARG_HOST | Default server host binding address. | 127.0.0.1 |
LLAMA_ARG_PORT | Default server port. | 8080 |
LLAMA_API_KEY | API key for server authentication. | None |
LLAMA_ARG_CTX_SIZE | Default context window size for the server. | 0 (model default) |
LLAMA_ARG_N_PARALLEL | Default number of parallel request slots. | 4 |
LLAMA_ARG_N_PREDICT | Default maximum tokens per generation. The -1 sentinel resolves to the effective per-slot context window. | -1 |
LLAMA_ARG_TIMEOUT | HTTP socket read/write timeout in seconds. Does not cancel a slow generation. | 3600 |
MLXCEL_DECODE_TIMEOUT | Per-request decode watchdog in seconds: cancels a request whose generation stops producing tokens. | 600 |
LLAMA_ARG_SPEC_DRAFT_N_MAX | The --draft-max value. LLAMA_ARG_DRAFT_MAX is read when this one is unset. The server reports it as n_max in /props; the proposal width comes from LLAMA_ARG_DRAFT_BLOCK_SIZE. | 16 |
LLAMA_ARG_MODEL_DRAFT | Drafter checkpoint path for the standalone mlxcel-server binary. | None |
LLAMA_ARG_DRAFT_KIND | Drafter kind override: dflash, mtp, full-model, or prompt-lookup. MLXCEL_DRAFT_KIND is the mlxcel-native alias. | Auto-detect |
LLAMA_ARG_DRAFT_BLOCK_SIZE | Draft block size for DFlash, MTP, full-model, and prompt-lookup. MLXCEL_DRAFT_BLOCK_SIZE is the mlxcel-native alias. | Resolved at startup from the drafter, device, and target quantization |
LLAMA_ARG_CACHE_REUSE | llama.cpp-compatible alias for prompt-cache enablement. | See MLXCEL_PROMPT_CACHE_ENABLED |
MLXCEL_PROMPT_CACHE_ENABLED | Enable prompt-prefix KV cache. Accepts true/false, 1/0, on/off. | true |
MLXCEL_PROMPT_CACHE_CAPACITY_BYTES | Prompt-cache byte budget. | 2147483648 |
MLXCEL_PROMPT_CACHE_MAX_ENTRIES | Prompt-cache entry cap. | 1024 |
MLXCEL_PROMPT_CACHE_TTL | Prompt-cache TTL in seconds. | 3600 |
MLXCEL_PROMPT_CACHE_MIN_PREFIX | Minimum token prefix length eligible for caching. | 32 |
APC_ENABLED | Automatic Prefix Caching block-hash layer. | true |
APC_BLOCK_SIZE | Tokens per APC block. | 16 |
APC_NUM_BLOCKS | APC entry cap. | Derived |
APC_HASH | APC hash algorithm: sha256 or blake3. | sha256 |
MLXCEL_AUDIO_QUEUE_DEPTH | Waiting commands in the audio worker queue. | 8 |
MLXCEL_AUDIO_REQUEST_TIMEOUT_SECS | Audio worker reply timeout. | 120 |
LLAMA_ARG_RESPONSES_STORE_MAX_ENTRIES | Maximum stored /v1/responses objects. | 1024 |
LLAMA_ARG_RESPONSES_STORE_TTL_SECS | /v1/responses store TTL in seconds. | 3600 |
LLAMA_ARG_CONVERSATION_STORE_MAX_ENTRIES | Maximum stored Responses API conversation transcripts. | 256 |
LLAMA_ARG_CONVERSATION_STORE_TTL_SECS | Conversation transcript TTL in seconds. | 3600 |
MLXCEL_SERVER_DECODE_STORAGE | Continuous-batching decode storage backend: auto, dense, or paged. | auto |
MLXCEL_VIDEO_DIR_ALLOWLIST | Comma-separated directory allowlist for local video_url files. Empty means fail-closed. Resolved once at startup for both native-video families and the frames fallback, so restart after changing it or after creating a listed directory. | Empty |
MLXCEL_REQUEST_MEMORY_BUDGET | Per-request memory budget for single-slot Metal Nemotron-H serving. It can only lower the budget derived from the runtime memory caps; an invalid value (zero, none, empty, non-finite, or overflowing) stops startup. | Derived from runtime caps |
LLAMA_LOG_FILE | Path to write server logs. | None (stderr) |
Note: Variables prefixed with
LLAMA_ARG_are intentional compatibility aliases. They allow mlxcel to be used as a drop-in replacement for llama-server in scripts and deployment configurations that already set these variables.
Device Selection¶
How Device Selection Works¶
When mlxcel starts, it selects a compute device in this order:
- If
MLXCEL_DEVICEis set tocpu, the CPU is used unconditionally. - If
MLXCEL_DEVICEis set togpuormetal, the GPU is used (an error is raised if no GPU is available). - Otherwise, the GPU is used automatically if available, and the CPU is used as a fallback.
On Apple Silicon, the GPU is the Metal-accelerated unified memory device. On Linux, it is the first CUDA-capable GPU (cuda:0). There is currently no multi-GPU round-robin within a single process; multi-GPU support is handled through the distributed inference features.
Forcing CPU Mode¶
CPU mode is useful for debugging model correctness or running on machines without compatible GPU hardware:
CPU inference is significantly slower than GPU inference for most models. It is not recommended for production use.
Memory Management¶
The Wired Memory Concept¶
On Apple Silicon, MLX uses "wired memory", memory that is pinned and cannot be swapped to disk. Wired memory is critical for performance because GPU operations require memory to be resident. However, over-wiring can cause system instability or OOM (out-of-memory) errors if other applications also need memory.
The MLXCEL_WIRED_LIMIT variable controls how much GPU memory mlxcel is allowed to wire.
Accepted Values¶
| Value | Behavior |
|---|---|
unset or max | Wire up to the GPU maximum at startup. This matches Python mlx-lm's wired-limit context behavior. |
0 or none | No wired limit. mlxcel does not configure a wired memory ceiling. |
96GB, 48GB, etc. | Wire up to the specified amount. Supports GB, MB, and bare byte counts. |
unlimited | Alias for max. |
Choosing a Wired Limit¶
For most users running mlxcel as the primary GPU workload on a dedicated machine, leaving MLXCEL_WIRED_LIMIT unset (the default) is the correct choice: mlxcel sets the wired limit to the GPU maximum, matching the mlx-lm pattern for keeping model weights resident.
If you experience memory pressure from other processes, set an explicit limit:
# Reserve 96 GB for mlxcel on a 128 GB system, leaving 32 GB for the OS and other apps
MLXCEL_WIRED_LIMIT=96GB mlxcel serve -m ./models/my-large-model --port 8080
Important: On Linux (CUDA),
MLXCEL_WIRED_LIMIThas no effect. CUDA memory management is handled by the CUDA runtime. Use standard CUDA environment variables (CUDA_VISIBLE_DEVICES, etc.) to control GPU allocation on Linux.
Server Configuration¶
Server configuration is applied via command-line flags when starting mlxcel serve or mlxcel-server. Many flags also read from environment variables (documented in the table above).
Networking and Authentication¶
| Flag | Environment Variable | Default | Description |
|---|---|---|---|
--host HOST | LLAMA_ARG_HOST | 127.0.0.1 | Address to bind the HTTP server to. Use 0.0.0.0 to accept connections from all interfaces. |
--port PORT | LLAMA_ARG_PORT | 8080 | TCP port to listen on. |
--api-key KEY | LLAMA_API_KEY | None | When set, all API endpoints (except /health and /) require Authorization: Bearer <key>. |
--api-key-file PATH | None | None | Read the API key from a file (whitespace trimmed). Takes precedence over --api-key. |
--timeout SECONDS | LLAMA_ARG_TIMEOUT | 3600 | HTTP socket read/write timeout, matching llama-server b10621. Bounds one socket read or write, not the generation. |
--decode-timeout SECONDS | MLXCEL_DECODE_TIMEOUT | 600 | Per-request decode watchdog: cancels a request whose generation stops producing tokens. |
--alias NAME | LLAMA_ARG_ALIAS | None | Model alias shown in API responses instead of the directory name. |
Example: start the server accessible from the local network, with authentication:
mlxcel serve \
--model ./models/llama-3.1-8b-4bit \
--host 0.0.0.0 \
--port 8080 \
--api-key my-secret-key
Generation Defaults¶
These flags set the default sampling parameters applied to requests that do not specify their own values. Per-request parameters always take precedence over these defaults.
| Flag | Default | Description |
|---|---|---|
--ctx-size N | 0 (model default) | Context budget in tokens. 0 uses the model's configured maximum; an explicit value is shared across active server slots. |
--n-predict N | -1 | Maximum tokens to generate per request. -1 resolves to the effective per-slot context window (or the 4096-token fallback if neither a server nor model limit is available). |
--temp FLOAT | 0.8 | Default sampling temperature. 0.0 is greedy (deterministic). |
--top-p FLOAT | 0.9 | Default nucleus sampling threshold. |
--top-k N | 40 | Default top-K sampling limit. 0 disables top-K filtering. |
--min-p FLOAT | 0.1 | Default min-P sampling threshold. 0.0 disables min-P filtering. |
--seed N | None | Default random seed for reproducible outputs. |
--repeat-last-n N | 64 | Context window size for repetition penalty. |
--repeat-penalty FLOAT | 1.0 | Repetition penalty multiplier. Values above 1.0 discourage repetition. |
--frequency-penalty FLOAT | 0.0 | Frequency penalty subtracts proportionally to how often a token has appeared. |
--presence-penalty FLOAT | 0.0 | Presence penalty subtracts a flat amount for any token that has appeared. |
--dry-multiplier FLOAT | 0.0 | DRY (Don't Repeat Yourself) penalty multiplier. 0.0 disables DRY. |
--dry-base FLOAT | 1.75 | DRY exponential base for scaling the penalty with match length. |
--dry-allowed-length N | 2 | Minimum suffix match length before DRY penalty applies. |
--dry-penalty-last-n N | -1 | DRY lookback window. -1 uses the full context. |
Continuous Batching¶
Continuous batching allows mlxcel to serve multiple concurrent requests efficiently by grouping their decode steps into a single forward pass. This significantly improves throughput under load without increasing latency for individual requests.
| Flag | Default | Description |
|---|---|---|
--n-parallel N, --parallel N | 4 | Number of parallel request slots. This is the primary control for concurrency and the default divisor for an explicit --ctx-size. |
--max-batch-size N | Same as --n-parallel | Maximum sequences in the active decode batch. When set, this is the divisor for an explicit --ctx-size. |
--max-queue-depth N | 32 | Maximum requests waiting in the prefill queue before new requests are rejected. |
--prefill-chunk-size N | 2048 idle, 512 with live decode | Tokens per prefill chunk. Long prompts are split into chunks of this size, with decode steps interleaved between chunks so active sequences are not starved. When unset, the server uses 2048 while no other sequence is decoding and 512 while a decode batch is live. An explicit value, -b/--batch-size (LLAMA_ARG_BATCH), or MLXCEL_PREFILL_CHUNK pins both states to one size. Set 0 to disable chunking. |
--prefill-grant-interval N | 16 | Guaranteed-prefill fairness interval in decode ticks. Lower values improve TTFT and raise decode ITL; 0 disables the grant. |
--max-batch-prefill N | 4 | Maximum queued requests to combine into one batched prefill pass. |
--max-batch-prefill-tokens N | derived | Padded-token budget for one batched prefill; 0 disables the cap. When unset, it is 2 * max_batch_prefill * min(prefill_chunk_size, 512) (4096 at the defaults). |
--enable-preemption | Disabled | When enabled, a high-priority request can evict a lower-priority active sequence (which is re-queued for re-prefill). |
--preemption-policy POLICY | longest-first | Eviction victim selection. longest-first evicts the sequence with the most generated tokens; lowest-priority evicts the lowest-priority sequence. |
--no-batch | Disabled | Disable the batch scheduler and use legacy sequential processing (one request at a time), preserving the full explicit --ctx-size for that single slot. |
--max-kv-size N | 0 | Cap plain, non-sliding KV caches to N tokens per sequence. 0 leaves them unbounded. |
--decode-storage-backend auto\|dense\|paged | auto | Select the continuous-batching decode storage backend. |
--kv-cache-budget BYTES\|auto\|none | auto | Paged KV block budget (MLXCEL_KV_CACHE_BUDGET). auto derives it from the memory estimate; none or 0 leaves the pool unbounded. Applies only to the paged decode backend. |
--kv-admission-watermark FRACTION | 0.01 | Share of the paged KV block budget, in 0.0..=0.5, that a prefill admission keeps free while rows are decoding (MLXCEL_KV_ADMISSION_WATERMARK). To make that room, admission evicts cold prompt-cache prefixes and, for a higher-priority request, preempts strictly lower-priority rows. A request that fits the budget is never refused. 0 disables it; it has no effect without a block budget. |
For llama.cpp compatibility, --ctx-size C is interpreted as a total context budget for the server when C > 0. The effective per-slot context window is floor(C / active_slots), where active_slots is --max-batch-size when explicitly set, otherwise --n-parallel; --no-batch uses one slot. /health.context_size, /slots[].context_size, and --estimate-memory use this effective per-slot value. Startup rejects explicit budgets that would leave a slot below 512 tokens.
Example: configure a server for high-concurrency use:
mlxcel serve \
--model ./models/llama-3.1-8b-4bit \
--port 8080 \
--n-parallel 8 \
--max-batch-size 8 \
--max-queue-depth 64 \
--prefill-chunk-size 512
The explicit --prefill-chunk-size 512 in this example pins the chunk at 512 for both idle and contended ticks; omit it to keep the adaptive 2048/512 default. See Continuous Batching for how chunking and the KV admission watermark interact with the scheduler.
Speculative Decoding¶
Speculative decoding accelerates generation by using a drafter to propose tokens that the target model verifies. Server mode supports the DFlash and MTP drafter kinds, an ordinary smaller checkpoint as a full-model drafter, and drafter-free prompt lookup (--draft-kind prompt-lookup).
| Flag | Default | Description |
|---|---|---|
--draft-model PATH | None | Drafter checkpoint. Both server binaries accept --draft-model PATH and --model-draft PATH; their help output presents a different primary spelling. |
--draft-max N | 16 | Accepted for llama-server compatibility (aliases --draft, --spec-draft-n-max, --draft-n). The value is reported as n_max in /props; it does not set the proposal width, which comes from --draft-block-size. |
--draft-kind dflash\|mtp\|full-model\|prompt-lookup | auto | Force a drafter kind. full-model runs an ordinary smaller checkpoint that shares the target's tokenizer, and a readable model directory that is neither MTP nor DFlash is detected as full-model. prompt-lookup takes no drafter checkpoint (a --draft-model with it fails startup). Omitted values are auto-detected from the drafter config. See Prompt Lookup in mlxcel. |
--draft-block-size N | resolved at startup | DFlash, MTP, or full-model block size. When unset, a width the drafter declares wins, then a measured per-device default, then 4 for MTP and full-model and 16 for DFlash; see Draft Block Width. With --draft-kind prompt-lookup it sets the largest proposal per round (default 7). |
--prompt-lookup-max-batch N | 2 | Largest active decode batch at which a prompt-lookup row runs its own verify round. With more concurrent rows, every row takes the plain batched step. Must be at least 1. |
DFlash example:
mlxcel serve \
--model ./models/qwen3.5-27b-4bit \
--draft-model ./models/Qwen3.5-27B-DFlash \
--draft-kind dflash \
--draft-block-size 16 \
--port 8080
Chat Templates¶
mlxcel automatically reads the chat template from the model's tokenizer_config.json. You can override this with a custom template.
| Flag | Default | Description |
|---|---|---|
--chat-template TEMPLATE | None | Override with an inline Jinja2 template string. |
--chat-template-file PATH | None | Override with a Jinja2 template file. |
Template resolution order:
--chat-template(inline string)--chat-template-file(file path)tokenizer_config.jsonchat_templatefield (automatic)- Built-in fallback template
Optional Endpoints¶
| Flag | Default | Description |
|---|---|---|
--metrics | Disabled | Enable the /metrics endpoint (Prometheus-compatible text format). |
--props | Disabled | Enable the /props endpoint (server properties). |
--no-slots | Enabled by default | Disable the /slots endpoint. |
Warmup¶
By default, the server generates one token on startup (and discards it) to pre-compile the Metal or CUDA compute pipeline. This eliminates latency on the first real request.