Modal is a serverless cloud platform for running Python on demand, including on-demand GPUs. Use when deploying or serving AI/ML models, running GPU-accelerated workloads (training, fine-tuning, inference), serving web endpoints, scheduling batch jobs, or scaling Python code to cloud containers with the Modal SDK.
SKILL.md
Modal
Overview
Modal is a cloud platform for running Python code serverlessly, with a focus on AI/ML workloads. Key capabilities:
Need persistent cloud storage for model weights or datasets
Want to run code in custom container environments
Build job queues or async task processing systems
Installation and Authentication
Install
uv pip install modal
The Modal Python SDK supports Python 3.10–3.14. This skill targets the stable modal>=1.0 API (current release: 1.4.x).
Authenticate
Prefer existing credentials before creating new ones. Only the two Modal-specific
variables below are relevant — do not read, load, or expose any other environment
variables or file contents:
.env
Check whether MODAL_TOKEN_ID and MODAL_TOKEN_SECRET are already set in the current environment.
If not, look up only those two keys in a local .env file (ignore all other entries) and load them if appropriate for the workflow.
Only fall back to interactive modal setup or generating fresh tokens if neither source already provides those two values.
modal setup
This opens a browser for authentication. For CI/CD or headless environments, use environment variables:
Enable concurrent request handling per container with @modal.concurrent. Set
target_inputs (the autoscaler's per-container target) below max_inputs (the hard
cap) to keep headroom while scaling up:
Reconfigure a deployed Function or Cls at invocation time without redeploying using
Function.with_options() / Function.with_concurrency() / Function.with_batching()
(and Cls.with_options()):
Model = modal.Cls.from_name("my-app", "Model")
fast = Model.with_options(gpu="H200", max_containers=20)
fast().generate.remote(prompt)
Reference: See references/scaling.md for .map(), .starmap(), .spawn(), and limits.
Defaults: 0.125 CPU cores, 128 MiB memory. Billed on max(request, usage).
Reference: See references/resources.md for limits and billing details.
Classes with Lifecycle Hooks
For stateful workloads (e.g., loading a model once and serving many requests):
@app.cls(gpu="L40S", image=image)
class Predictor:
@modal.enter()
def load_model(self):
self.model = load_heavy_model() # Runs once on container start
@modal.method()
def predict(self, text: str):
return self.model(text)
@modal.exit()
def cleanup(self):
... # Runs on container shutdown
Call with: Predictor().predict.remote("hello")
Sandboxes
For running untrusted or dynamically generated code (for example, AI-agent output or a code interpreter), use a modal.Sandbox — an isolated container you create and control programmatically rather than a decorated Function:
app = modal.App.lookup("sandbox-demo", create_if_missing=True)
# Isolated container; restrict egress for untrusted workloads
sb = modal.Sandbox.create(
app=app,
image=modal.Image.debian_slim(),
outbound_cidr_allowlist=["10.0.0.0/8"],
)
# Stream files in/out via the filesystem API (beta)
sb.filesystem.write_text("print(2 ** 10)\n", "/tmp/job.py")
contents = sb.filesystem.read_text("/tmp/job.py")
sb.terminate()
Run commands inside the sandbox with its exec method (e.g. run python /tmp/job.py) and read stdout from the returned process handle — see references/api_reference.md
Restrict connectivity with outbound_cidr_allowlist=[...] / inbound_cidr_allowlist=[...]
Snapshot the filesystem with sb.snapshot_filesystem() to reuse as a base image
Ideal for code interpreters, agent tool execution, and per-user isolation
Credentials: Only MODAL_TOKEN_ID and MODAL_TOKEN_SECRET are needed to authenticate. Do not read, log, or forward any other environment variables or .env entries.
Subprocess / custom servers: Some patterns here (multi-GPU training launchers, @modal.web_server apps) call subprocess.run/subprocess.Popen or shell commands during builds. Keep argument lists fixed and hardcoded. Never construct subprocess or shell arguments from unsanitized user input — pass untrusted values as data (files, env vars, stdin), not as command arguments.
Untrusted code: Run user- or model-generated code inside a modal.Sandbox (see above), not a regular Function, and restrict network access with CIDR allowlists.
Reference Files
Detailed documentation for each topic:
references/getting-started.md — Installation, authentication, first app