Runs vs. Threads: When to Use Which

Published: (March 5, 2026 at 06:00 AM EST)
8 min read
Source: Dev.to

Source: Dev.to

Cover image for Runs vs. Threads: When to Use Which

Valentina

Crewship has two ways to execute a deployed crew: the Run API and the Thread API. If you’ve used the platform at all, you’ve already used runs. Threads are newer and less obvious, and the question we keep hearing is: when should I use which?

Runs are for one‑shot tasks. Threads are for conversations. That’s the short version. The rest of this post is the long version.

Runs: the default

A run is a single execution of your crew. You send input, it does its thing, you get output. Each run gets its own container, shares nothing with other runs, and the environment is torn down when it finishes.

crewship invoke --input '{"topic": "AI agents in logistics"}'

Or via the API:

curl -X POST https://api.crewship.dev/v1/runs \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"deployment_id": "dep_abc123", "input": {"topic": "AI agents in logistics"}}'

You get back a run ID. The run moves through pending → running → succeeded/failed/canceled. You can stream events in real time to watch your agents work, or just poll for the result.

No setup, no cleanup, no state to manage.

When runs make sense

Runs are the right choice when your crew’s job starts and ends in a single execution:

  • “Write a blog post about X” – input in, content out, done.
  • “Analyze this dataset and generate a report” – same deal.
  • Batch operations that process a list of items independently.
  • Background jobs triggered by a webhook or a cron schedule.
  • Pipeline steps where your crew is one stage in a larger workflow.

The common pattern: the crew doesn’t need to ask clarifying questions, doesn’t need to remember what happened last time. It takes input and produces output, and that’s the whole interaction.

What runs don’t do

Runs are stateless. When a run finishes, it’s gone. If you kick off another run with the same deployment, it has zero context about the previous one. It doesn’t know you ran it five minutes ago with slightly different input, nor that the last output was almost right but needed a tweak.

For many workloads that’s exactly what you want, but for some it’s a problem.

Threads: when you need memory

A thread is a persistent conversation context scoped to a deployment. You create it once, then run your crew inside it as many times as you need. Each run receives the thread’s current state, and when the run finishes it can update that state. The next run picks up where the last one left off.

# Create a thread
crewship thread create dep_abc123

# Run inside it
crewship invoke dep_abc123 --thread thr_xyz789 -i '{"message": "Research AI agents in healthcare"}'

# Follow‑up – the crew remembers the first message
crewship invoke dep_abc123 --thread thr_xyz789 -i '{"message": "Now focus on diagnostic applications"}'

Via the API:

# Create the thread
curl -X POST https://api.crewship.dev/v1/threads \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"deployment_id": "dep_abc123"}'

# Run inside it
curl -X POST https://api.crewship.dev/v1/threads/thr_xyz789/runs \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input": {"message": "Research AI agents in healthcare"}}'

The thread tracks state through a values field — a JSON object that your crew can read and write. After each run, Crewship saves a checkpoint, giving you a full history of how the state changed over time.

Thread lifecycle

Threads have their own status:

StatusMeaning
idleReady for a new run
busyA run is executing; new run requests get a 409 until it ends
interruptedThe run was interrupted
errorThe last run failed, but the thread still accepts new runs

Only one run can execute in a thread at a time. This design keeps state consistent and prevents concurrent runs from stepping on each other’s updates.

When threads make sense

Threads shine wherever context carries over between interactions:

  • Conversational agents – chatbots or support assistants where each user message builds on the previous exchange.
  • Iterative refinement – e.g., “Generate a marketing plan,” then “Make the budget section more detailed,” then “Add a timeline.” Each run builds on the prior output.
  • Multi‑step workflows with human approval – the crew does research, presents findings, waits for user direction, then proceeds. The thread holds intermediate state without you having to manage it.

Checkpoints

Every time a run inside a thread finishes, Crewship creates a checkpoint that records the thread’s values at that moment. You can retrieve the full history of checkpoints to:

  • Audit how the state evolved.
  • Roll back to a previous state if needed.
  • Debug unexpected behavior by inspecting past values.

TL;DR

  • Runs = one‑off, stateless executions. Use them for isolated tasks, batch jobs, or any situation where no memory of previous runs is required.
  • Threads = stateful, sequential executions. Use them for conversations, iterative work, or workflows that need to preserve context across multiple calls.

Choose the right tool for the job, and let Crewship handle the heavy lifting!

Checkpoints

Crewship saves a checkpoint — a snapshot of the thread’s state at that moment.

curl https://api.crewship.dev/v1/threads/thr_xyz789/history \
  -H "Authorization: Bearer YOUR_API_KEY"

This gives you an audit trail. It’s also useful for debugging: if the crew’s response went sideways on turn 5, you can look at the checkpoint from turn 4 to see what state it was working with.

Thread metadata

Threads support a metadata field that’s separate from the conversation state. Use it for things like user IDs, channels, tags — anything you want to filter or search by later:

curl -X POST https://api.crewship.dev/v1/threads \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "deployment_id": "dep_abc123",
    "metadata": {
      "user_id": "user_42",
      "channel": "web",
      "priority": "high"
    }
  }'

This matters once you have hundreds of threads across different users and use cases.

Side‑by‑side comparison

FeatureRunsThreads
StateNone — each run is isolatedPersistent across runs via values
Lifecyclependingrunning → terminalidlebusyidle (repeats)
ConcurrencyUnlimited parallel runsOne run at a time per thread
HistoryIndividual run recordsCheckpoints after each run
SetupNone — just create a runCreate thread first, then run inside it
CleanupAutomaticManual — delete thread when done
Cost profilePredictable per runGrows with conversation length

How other platforms handle this

If you’ve used other agent platforms, you’ll recognize the split. OpenAI’s Assistants API had Threads and Runs — literally the same names. They’ve since replaced it with the Responses API and Conversations, but the idea is identical: a stateless execution primitive and an optional persistence layer.

  • LangGraph – Call graph.invoke() for a one‑shot execution. Pass a thread_id to get persistence, checkpoints, and the ability to resume from any point.
  • CrewAIkickoff() is the one‑shot execution; a separate conversational mode provides multi‑turn interactions.

The pattern across all of these: runs are the execution primitive; threads (or their equivalents) optionally chain runs together with shared state. You don’t need threads until you do.

So which one should you use?

One question gets you most of the way there: Does the crew need to remember anything from previous executions?

AnswerRecommendation
NoUse a run. Adding a thread only adds unnecessary complexity.
YesUse a thread. Trying to fake statefulness by jam‑ming prior context into run inputs quickly becomes messy, and you lose checkpoints, history, and the concurrency guarantees that threads provide.

Signals that point toward threads

  • Users will interact with the crew multiple times per session.
  • The crew’s output depends on conversation history rather than just the current input.
  • You need an audit trail of how state evolved over time.

Signals that point toward runs

  • The crew can do its job with a single set of inputs.
  • You want to fire off many executions in parallel.
  • The workload is triggered by an automated system rather than a person sending messages.

Getting started with threads

If you’ve been using runs and want to try threads, there’s nothing to change about your deployment. Threads work with any deployed crew — CrewAI, LangGraph Python, or LangGraph JS.

# Create a thread
crewship thread create dep_abc123 --metadata '{"user_id": "demo"}'

# First turn
crewship invoke dep_abc123 --thread thr_xyz789 \
  -i '{"message": "What can you help me with?"}'

# Second turn — crew receives context from the first
crewship invoke dep_abc123 --thread thr_xyz789 \
  -i '{"message": "Tell me more about option 2"}'

# Check the history
crewship thread history thr_xyz789

Full API reference is in the threads documentation.

Questions about runs, threads, or anything else? Check the docs or reach out at .

0 views
Back to Blog

Related posts

Read more »