Skip to main content
MindStudio
Pricing
Blog About
My Workspace

How to Deploy Claude Agents to Modal and Trigger.dev: A No-Code Guide

Learn how to deploy Claude Code skills to Modal (Python) or Trigger.dev (TypeScript) so your AI agents run 24/7 without your machine staying on.

MindStudio Team RSS
How to Deploy Claude Agents to Modal and Trigger.dev: A No-Code Guide

Why Running Claude Agents Locally Doesn’t Scale

If you’ve built a Claude-powered agent that works great on your laptop, you’ve already hit the core problem: the moment you close the terminal, the agent stops.

That’s fine for experiments. It’s not fine for anything production-ready — scheduled jobs, webhook listeners, background processors, or agents that need to handle requests at any hour. Deploying Claude agents to Modal (Python) or Trigger.dev (TypeScript) solves this by giving your agent a persistent, cloud-based home that runs 24/7 without your machine staying on.

This guide walks through both deployment paths step by step. Whether you’re working in Python or TypeScript, you’ll have a running Claude agent in the cloud by the end.


What Modal and Trigger.dev Actually Are

Before touching any code, it’s worth being clear about what each platform does — and why they’re worth using over raw cloud VMs or serverless functions.

Modal is a serverless compute platform built specifically for Python workloads. You write a normal Python function, decorate it with Modal-specific decorators, and Modal handles all the infrastructure: containerization, scaling, GPU access, scheduling, and cold start optimization.

For Claude agents, Modal is a strong fit if:

  • Your agent code is Python-based
  • You’re using Anthropic’s Python SDK directly
  • You want scheduled runs (cron jobs) or on-demand execution via a web endpoint
  • You need access to GPU resources for hybrid AI workloads

Trigger.dev: Background Jobs for TypeScript

Day one: idea. Day one: app.

DAY
1
DELIVERED

Not a sprint plan. Not a quarterly OKR. A finished product by end of day.

Trigger.dev is an open-source background job platform for TypeScript and Node.js. It provides durable execution — meaning if a job fails halfway through, it can resume from where it left off rather than starting over. It also has built-in support for long-running tasks, retries, concurrency limits, and a clean dashboard for monitoring runs.

For Claude agents, Trigger.dev is a strong fit if:

  • Your agent logic is TypeScript/Node.js
  • You’re calling the Anthropic SDK via @anthropic-ai/sdk
  • You need webhook-triggered agents or event-driven execution
  • Reliability and observability matter more than raw speed

Both platforms have generous free tiers that are more than enough to get started.


Prerequisites

Before deploying, make sure you have the following ready regardless of which platform you choose:

  • An Anthropic API key — Get one from the Anthropic Console
  • A basic Claude agent already working locally — This guide assumes you have agent code running on your machine
  • Node.js 18+ or Python 3.10+ depending on your path
  • A Modal or Trigger.dev account — both are free to create

Deploying a Claude Agent to Modal (Python Path)

Step 1: Install Modal and Set Up Authentication

Install Modal with pip:

pip install modal

Then authenticate with your Modal account:

modal setup

This opens a browser window to link your account. Once done, Modal stores your credentials locally so future deployments work without re-authenticating.

Step 2: Store Your Anthropic API Key as a Modal Secret

Never hardcode API keys in your code. Modal has a built-in secrets system.

In the Modal dashboard, go to Secrets, click Create new secret, and add:

  • Key: ANTHROPIC_API_KEY
  • Value: your actual API key

Name the secret something like anthropic-secret. You’ll reference this name in your code.

Step 3: Write Your Modal-Compatible Agent

Here’s a minimal Claude agent structure that Modal can run:

import modal
import anthropic

app = modal.App("claude-agent")

image = modal.Image.debian_slim().pip_install("anthropic")

@app.function(
    image=image,
    secrets=[modal.Secret.from_name("anthropic-secret")],
    schedule=modal.Cron("0 9 * * *")  # runs every day at 9am UTC
)
def run_claude_agent():
    client = anthropic.Anthropic()
    
    message = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": "Summarize the key actions I should take this week based on the following data..."
            }
        ]
    )
    
    result = message.content[0].text
    print(result)
    return result

A few things to note here:

  • modal.Image.debian_slim().pip_install("anthropic") builds a container image with the Anthropic SDK installed
  • modal.Secret.from_name("anthropic-secret") injects your API key as an environment variable
  • modal.Cron("0 9 * * *") schedules the function to run daily at 9am UTC — remove this for on-demand runs

Step 4: Add a Web Endpoint (Optional but Useful)

If you want to trigger your agent via HTTP — for example, from a webhook — add a web endpoint:

@app.function(
    image=image,
    secrets=[modal.Secret.from_name("anthropic-secret")]
)
@modal.web_endpoint(method="POST")
def agent_webhook(request: dict):
    client = anthropic.Anthropic()
    
    user_input = request.get("message", "")
    
    message = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": user_input}]
    )
    
    return {"response": message.content[0].text}

Modal will give you a public HTTPS URL for this endpoint after deployment.

Step 5: Deploy to Modal

Run this from your project directory:

modal deploy your_agent_file.py

Modal builds the container, pushes it, and gives you a deployment URL. Scheduled functions will now run on their own schedule. Web endpoints will be live immediately.

To test a function manually before the schedule triggers:

modal run your_agent_file.py::run_claude_agent

Step 6: Monitor Your Agent

REMY IS NOT
  • a coding agent
  • no-code
  • vibe coding
  • a faster Cursor
IT IS
a general contractor for software

The one that tells the coding agents what to build.

The Modal dashboard shows every function invocation, stdout output, errors, and execution time. You can also set up log streaming in your terminal:

modal app logs claude-agent

Deploying a Claude Agent to Trigger.dev (TypeScript Path)

Step 1: Install the Trigger.dev CLI and Initialize a Project

Install the CLI globally:

npm install -g @trigger.dev/cli

If you’re starting from scratch, initialize a new project:

npx trigger.dev@latest init

If you’re adding Trigger.dev to an existing Node.js project:

npx trigger.dev@latest init --existing

The CLI will ask for your Trigger.dev project reference (found in your dashboard after creating an account). It creates a trigger folder in your project with a sample task file.

Step 2: Install the Anthropic SDK

npm install @anthropic-ai/sdk

Step 3: Store Your API Key

In the Trigger.dev dashboard, navigate to Environment Variables and add:

  • ANTHROPIC_API_KEY = your API key

This makes the variable available to all your tasks at runtime without exposing it in code.

Step 4: Write Your Trigger.dev Task

Tasks are the core unit of work in Trigger.dev. Here’s a Claude agent task:

import { task, schedules } from "@trigger.dev/sdk/v3";
import Anthropic from "@anthropic-ai/sdk";

export const claudeAgentTask = task({
  id: "claude-agent-task",
  maxDuration: 300, // 5 minutes max
  run: async (payload: { userMessage: string }) => {
    const client = new Anthropic();
    
    const message = await client.messages.create({
      model: "claude-opus-4-5",
      max_tokens: 1024,
      messages: [
        {
          role: "user",
          content: payload.userMessage
        }
      ]
    });
    
    const response = message.content[0].type === "text" 
      ? message.content[0].text 
      : "";
    
    console.log("Claude response:", response);
    
    return { response };
  }
});

For a scheduled version that runs on a cron, use Trigger.dev’s schedules:

import { schedules } from "@trigger.dev/sdk/v3";
import Anthropic from "@anthropic-ai/sdk";

export const scheduledClaudeAgent = schedules.task({
  id: "scheduled-claude-agent",
  cron: "0 9 * * 1-5", // weekdays at 9am UTC
  run: async (payload) => {
    const client = new Anthropic();
    
    const message = await client.messages.create({
      model: "claude-opus-4-5",
      max_tokens: 1024,
      messages: [
        {
          role: "user",
          content: "Generate today's morning briefing..."
        }
      ]
    });
    
    return { result: message.content[0] };
  }
});

Step 5: Run in Dev Mode to Test

Before deploying, test locally with:

npx trigger.dev@latest dev

This connects your local environment to Trigger.dev’s servers. You can trigger test runs from the dashboard and see real-time logs in your terminal. Your API key is pulled from the environment variables you set in the dashboard.

Step 6: Deploy

When you’re ready to go live:

npx trigger.dev@latest deploy

Trigger.dev builds your project in its cloud environment and registers your tasks. Scheduled tasks activate automatically. On-demand tasks wait for a trigger — either a manual run from the dashboard or an API call.

Step 7: Trigger Tasks via API

Once deployed, you can trigger any task via HTTP from any system:

curl -X POST https://api.trigger.dev/v1/tasks/claude-agent-task/trigger \
  -H "Authorization: Bearer YOUR_TRIGGER_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"payload": {"userMessage": "What are the key trends in Q3 data?"}}'

The response includes a run ID you can use to poll for results or stream logs.


Building Multi-Step Claude Agents

A single message to Claude is rarely a complete agent. Real-world agents need to call tools, make decisions across multiple steps, and act on results. Both Modal and Trigger.dev support this, but the patterns differ slightly.

Multi-Step Agents in Modal

Modal functions can call other Modal functions, making it easy to chain steps:

@app.function(image=image, secrets=[modal.Secret.from_name("anthropic-secret")])
def analyze_data(data: str) -> str:
    # Step 1: ask Claude to analyze
    ...

@app.function(image=image, secrets=[modal.Secret.from_name("anthropic-secret")])
def run_full_pipeline(raw_data: str):
    analysis = analyze_data.remote(raw_data)
    # Step 2: use analysis result in next call
    ...

The .remote() call runs the function in a separate container, which means each step scales independently.

Multi-Step Agents in Trigger.dev

Trigger.dev is purpose-built for this. Use subtasks or just chain await calls within a single task:

export const researchAndSummarizeTask = task({
  id: "research-and-summarize",
  run: async (payload: { topic: string }) => {
    const client = new Anthropic();
    
    // Step 1: gather questions
    const questionsResponse = await client.messages.create({
      model: "claude-opus-4-5",
      max_tokens: 512,
      messages: [{ role: "user", content: `Generate 5 research questions about: ${payload.topic}` }]
    });
    
    const questions = questionsResponse.content[0].type === "text" 
      ? questionsResponse.content[0].text 
      : "";
    
    // Step 2: synthesize answers
    const summaryResponse = await client.messages.create({
      model: "claude-opus-4-5",
      max_tokens: 1024,
      messages: [
        { role: "user", content: `Answer each of these questions concisely:\n${questions}` }
      ]
    });
    
    return { summary: summaryResponse.content[0] };
  }
});

Trigger.dev’s durable execution means if your task hits a timeout or error partway through, you can configure it to retry from the last successful checkpoint rather than starting over.


Common Mistakes and How to Avoid Them

Forgetting to Handle Rate Limits

Anthropic enforces rate limits per API key. If your agent runs many calls in a short window, you’ll get 429 errors. Always add retry logic:

In Python:

from anthropic import RateLimitError
import time

def call_claude_with_retry(client, messages, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.messages.create(
                model="claude-opus-4-5",
                max_tokens=1024,
                messages=messages
            )
        except RateLimitError:
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)  # exponential backoff
            else:
                raise

In TypeScript (Trigger.dev): Set retry on the task config:

export const claudeTask = task({
  id: "claude-task",
  retry: {
    maxAttempts: 3,
    factor: 2,
    minTimeoutInMs: 1000,
  },
  run: async (payload) => { ... }
});

Hardcoding Model Names

Anthropic updates model names regularly. Hardcoding claude-opus-4-5 in 20 places means 20 edits when a new version releases. Store the model name in an environment variable and reference it throughout.

Not Setting Max Execution Timeouts

By default, cloud functions have short timeouts. A complex Claude agent doing 10+ API calls can easily run for several minutes. Always set maxDuration in Trigger.dev and timeout in Modal explicitly to match your expected execution time.

Logging Too Much (or Too Little)

Log the inputs, outputs, and key decision points of your agent — but don’t log full message histories on every run at production scale. This inflates costs and makes it harder to find relevant logs. Use structured logging with severity levels.


Where MindStudio Fits Into This

Modal and Trigger.dev solve the infrastructure layer — where your agent runs and when. But they don’t solve what your agent can actually do. A Claude agent running in Modal can reason and generate text, but actually sending an email, writing to a spreadsheet, posting to Slack, or triggering another workflow requires extra code for each integration.

That’s where MindStudio’s Agent Skills Plugin changes the picture. It’s an npm SDK (@mindstudio-ai/agent) that gives any agent — including Claude agents deployed on Trigger.dev or Modal — access to 120+ pre-built capabilities as simple method calls.

Instead of writing custom integration code, your agent just calls:

import { MindStudioAgent } from "@mindstudio-ai/agent";

const agent = new MindStudioAgent({ apiKey: process.env.MINDSTUDIO_KEY });

// Send an email without writing email integration code
await agent.sendEmail({ to: "team@company.com", subject: "Agent Report", body: result });

// Generate an image
const image = await agent.generateImage({ prompt: "quarterly results chart" });

// Search the web
const searchResults = await agent.searchGoogle({ query: "latest AI benchmarks" });

The SDK handles auth, rate limiting, and retries for every integration — your agent just calls the method and gets the result. This pairs naturally with Claude agents deployed to Trigger.dev, where your task file can import both @anthropic-ai/sdk and @mindstudio-ai/agent and combine Claude’s reasoning with real-world actions in a single durable job.

If you’d rather skip the deployment complexity entirely, you can also build and host Claude-powered agents directly on MindStudio’s no-code platform. Agents run in the cloud by default, support custom JavaScript functions, and connect to 1,000+ integrations without any deployment configuration. You can try it free at mindstudio.ai.


Choosing Between Modal and Trigger.dev

Neither platform is universally better — they suit different situations.

FactorModalTrigger.dev
LanguagePythonTypeScript / Node.js
SchedulingBuilt-in cronBuilt-in cron
Durable executionNo (restart on failure)Yes (resume from checkpoint)
GPU accessYesNo
ObservabilityGoodExcellent
Open sourceNoYes
Free tierGenerous compute creditsGenerous task runs
Best forData-heavy Python agentsLong-running TypeScript workflows

If you’re already writing Python and your agent is compute-intensive or needs GPU access, Modal is the better fit. If you’re in TypeScript and need reliable, observable background jobs with durable execution, Trigger.dev is worth choosing.


Frequently Asked Questions

Do I need to know Docker or Kubernetes to deploy Claude agents to Modal or Trigger.dev?

No. Both platforms abstract away container management entirely. Modal builds containers from Python function definitions. Trigger.dev handles its own build process. You write application code — not infrastructure config.

How much does it cost to run a Claude agent on Modal or Trigger.dev?

Both have free tiers. Modal gives new accounts $30 in free compute credits per month, which is substantial for most agent workloads. Trigger.dev’s free plan includes 5,000 task runs per month. Costs scale with usage after that — a Claude agent running once per day or responding to occasional webhooks will likely stay in the free tier for a long time.

Can I use Claude’s tool use (function calling) feature with these platforms?

Everyone else built a construction worker.
We built the contractor.

🦺
CODING AGENT
Types the code you tell it to.
One file at a time.
🧠
CONTRACTOR · REMY
Runs the entire build.
UI, API, database, deploy.

Yes. Both platforms are just runtime environments — they don’t restrict how you call the Anthropic API. You can use Claude’s full API surface including tool use, vision, multi-turn conversations, and streaming responses. The deployment code in this guide is a starting point; add tool definitions to your client.messages.create() calls as you normally would.

What happens if my Claude agent fails mid-run?

In Modal, failed functions can be configured to retry automatically. In Trigger.dev, durable execution means tasks can resume from the last successful step rather than starting over — which is particularly valuable for long-running, multi-step agents. Either way, both platforms surface failure reasons in their dashboards so you can debug quickly.

Can I run a Claude agent that responds to webhooks on both platforms?

Yes. Modal supports web endpoints via @modal.web_endpoint, which gives you a public HTTPS URL. Trigger.dev tasks can be triggered via their REST API, and you can point any webhook at a lightweight API route that calls claudeAgentTask.trigger(). Both approaches work well for event-driven agent patterns.

Is it possible to run a Claude agent on a schedule without any server?

Yes — and that’s the main point of both platforms. Modal’s schedule=modal.Cron(...) and Trigger.dev’s schedules.task with a cron expression both run on cloud infrastructure without needing a server you manage. The agent wakes up on schedule, runs, and shuts down — you pay only for execution time.


Key Takeaways

  • Modal is the right choice for Python-based Claude agents, especially if you need GPU access or want a simple serverless function model.
  • Trigger.dev is better for TypeScript agents where durable execution, observability, and long-running jobs matter.
  • Both platforms handle secrets management, scheduling, and scaling — don’t store API keys in code.
  • Add retry logic for Anthropic rate limits regardless of which platform you use.
  • The MindStudio Agent Skills Plugin extends deployed Claude agents with 120+ real-world capabilities — sending emails, generating images, searching the web — without writing custom integration code.

If you want to skip deployment entirely and build agents that run in the cloud by default, MindStudio lets you create and host Claude-powered workflows visually, with built-in integrations, in a fraction of the time. Try it free at mindstudio.ai.

Presented by MindStudio

No spam. Unsubscribe anytime.