LangGraph Deployment: Reliable Production Jobs¶

A LangGraph agent that works locally is not yet a production job. Production adds interrupted runs, concurrent schedules, expired credentials, duplicate side effects, and state that must survive a cold start.
A reliable LangGraph deployment needs more than an API endpoint. You need a small reproducible package, persistent checkpoints, stable thread identifiers, bounded retries, and a scheduler that cannot launch conflicting work. This guide builds that operational layer around a LangGraph application without turning it into a large infrastructure project.
1. Choose the right LangGraph deployment model for a production job¶
LangGraph is the open source framework. LangSmith Deployment is the managed execution service. The latter was previously called LangGraph Platform and was renamed in October 2025, according to the LangSmith Deployment product page.
The deployment documentation presents four environments:
- Cloud
- Self-hosted with a control plane
- Hybrid
- Standalone server
Cloud is the shortest path when you want LangChain to manage the runtime. It runs on AWS and GCP. You can create deployments from GitHub or with langgraph deploy. It requires a Plus plan or higher.
Standalone shifts more responsibility to you. You deploy Agent Server with Docker, Compose, or Kubernetes. You must also provide PostgreSQL, Redis, and a LangSmith license. There is no control plane in this mode.
For a scheduled competitor-monitoring or reporting agent, make the choice based on ownership:
| Concern | Managed Cloud | Standalone |
|---|---|---|
| Runtime operations | Managed | Your responsibility |
| PostgreSQL and Redis | Managed as part of the platform | You provide them |
| Deployment path | GitHub or LangGraph CLI | Docker, Compose, or Kubernetes |
| Infrastructure control | Lower | Higher |
| Operational workload | Lower | Higher |
Do not choose standalone only because your application already has a Dockerfile. Database maintenance, backups, migrations, runtime upgrades, and alerts become part of the deployment.
Before selecting a runtime, map the complete path from source code to scheduled execution. This AI job deployment architecture overview provides a useful model for separating builds, configuration, execution, and storage.
2. Package the smallest deployable LangGraph application¶
Keep the repository boring. A production package should expose the graph clearly and make dependency resolution reproducible.
langgraph-report-job/
├── src/
│ └── report_agent/
│ ├── __init__.py
│ ├── graph.py
│ └── settings.py
├── tests/
│ └── test_import.py
├── langgraph.json
├── pyproject.toml
└── uv.lock
A minimal graph can start with one deterministic node:
#src/report_agent/graph.py
from typing import TypedDict
from langgraph.graph import END, START, StateGraph
class ReportState(TypedDict):
topic: str
status: str
def prepare_report(state: ReportState) -> ReportState:
return {
"topic": state["topic"],
"status": "prepared",
}
builder = StateGraph(ReportState)
builder.add_node("prepare_report", prepare_report)
builder.add_edge(START, "prepare_report")
builder.add_edge("prepare_report", END)
graph = builder.compile()
Expose that graph in langgraph.json:
Declare only runtime dependencies:
#pyproject.toml
[project]
name = "langgraph-report-job"
dynamic = ["version"]
dependencies = [
"langgraph"
]
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
Generate and commit a lockfile with the package manager used by CI. The exact dependency versions belong in that file, not in a blog example that will age.
Before deployment, test the same import path referenced by langgraph.json:
Fail the build if this command fails. It catches missing modules, packaging errors, and imports that depend on undeclared local files.
LangGraph applications can be deployed through application templates and the LangGraph CLI, as described in the LangSmith Deployment documentation. Keep the graph entry point independent of deployment-specific bootstrap code. That makes local tests and alternative runtimes easier.
For more build guidance, see smaller and reproducible Python deployments.
3. Configure environment variables, secrets, and runtime boundaries¶
Do not put API keys, database URLs, or environment-specific resource names in graph state or source code. Inject them at runtime and validate them before the graph accepts work.
#src/report_agent/settings.py
import os
from dataclasses import dataclass
@dataclass(frozen=True)
class Settings:
model_api_key: str
database_url: str
environment: str
@classmethod
def from_env(cls) -> "Settings":
required = ("MODEL_API_KEY", "DATABASE_URL", "APP_ENV")
missing = [name for name in required if not os.getenv(name)]
if missing:
names = ", ".join(missing)
raise RuntimeError(f"Missing required environment variables: {names}")
return cls(
model_api_key=os.environ["MODEL_API_KEY"],
database_url=os.environ["DATABASE_URL"],
environment=os.environ["APP_ENV"],
)
Run the validation during startup:
uv run python -c \
"from src.report_agent.settings import Settings; print(Settings.from_env().environment)"
Use separate credentials for development and production. Give the job access only to the APIs, database tables, and storage paths it needs. Never print secret values. Logs should contain configuration names and safe identifiers, not credentials.
The LangSmith Cloud quickstart requires GitHub and LangSmith accounts. It supports public and private GitHub repositories. Its documented deployment paths include GitHub and langgraph deploy. The quickstart also says a repository deployment can take about 15 minutes. See the LangGraph deployment quickstart for the managed flow.
Secret injection is only one boundary. Network access, database permissions, and tool capabilities also matter. Apply the patterns in this guide to AI agent secrets, IAM, and isolation.
4. Add persistent checkpoints for durable, resumable execution¶
A checkpoint is not the same as a final result.
After deployment, Agent Server uses:
- Assistants for configuration.
- Threads for state.
- Runs for workloads.
A thread gives related executions a stable state container. A run performs work against that thread. Checkpoints capture graph progress so execution can continue after an interruption.
For a scheduled report, derive a stable thread ID from the logical job:
Do not generate a random identifier every time the scheduler retries. A new identifier can create a separate state history instead of resuming the existing one.
If you operate the persistence layer, use a PostgreSQL-backed checkpointer and treat its schema like any production database:
- Run schema setup through a controlled migration step.
- Keep thread IDs stable.
- Verify that a checkpoint can be read after a process restart.
- Define retention rules.
- Back up the checkpoint database.
- Test restoration.
- Keep large artifacts in object storage and store references in graph state.
LangSmith Deployment materials describe durability across restarts and cold starts. They also describe persistent checkpoint payloads of up to 25 MB. Treat that as a ceiling, not a target. Source documents, generated reports, and binary artifacts should not inflate every checkpoint. See the LangSmith Deployment product details.
A small state model is easier to inspect and recover. The same principle is covered in this minimal persistent-state design for serverless jobs.
5. Design safe recovery, retries, idempotency, and observability¶
Imagine the agent summarizes several approved sources, writes a report, and then crashes before marking the run complete.
A safe recovery flow is:
- Record a stable job and thread ID before execution.
- Locate the interrupted run.
- Read the latest valid checkpoint.
- Resume unfinished graph work.
- Deduplicate external writes.
- Mark completion only after required side effects succeed.
The checkpoint prevents lost graph progress. It does not automatically make an email, webhook, or database write safe to repeat.
Create a deterministic idempotency key from the scheduled window:
import hashlib
def scheduled_run_id(job_name: str, scheduled_at_utc: str) -> str:
raw = f"{job_name}:{scheduled_at_utc}".encode()
return hashlib.sha256(raw).hexdigest()
Store that key with each external effect. Use an upsert or a uniqueness constraint where supported. A retry can then update or reuse the existing record instead of creating a duplicate.
Your runtime policy should also include:
- A timeout for each tool and for the complete run.
- Bounded retries for transient failures.
- A lock or conditional write that blocks overlapping runs.
- Dead-letter handling for work that exhausts retries.
- Structured logs containing job, thread, run, and checkpoint identifiers.
- Run-status metrics and alerts.
- A documented procedure for diagnosing blocked runs.
Log state transitions, not full prompts or secrets. Useful events include run_started, checkpoint_saved, effect_committed, run_resumed, and run_failed.
For implementation patterns, use stable IDs, upserts, and concurrency control for idempotent jobs. If execution can exceed a runtime limit, design it as a resumable long-running task.
6. Schedule the LangGraph agent and promote it safely to production¶
For an hourly job, a cron expression can be:
This triggers at minute zero of each hour. Decide whether the schedule is interpreted in UTC or a local time zone. UTC is usually easier to reason about. If business logic requires local time, record both the scheduled local time and its UTC equivalent.
Each invocation should receive a deterministic identifier:
run_id = scheduled_run_id(
job_name="competitor-summary",
scheduled_at_utc="2026-08-25T14:00:00Z",
)
Acquire a lock using that identifier before starting the graph. If the same schedule fires again while the first invocation is active, the duplicate should exit cleanly or observe the existing run.
LangSmith Deployment advertises cron-triggered agents, durable runtime behavior, background execution, and APIs for human-in-the-loop approvals. The deployment documentation also describes persistent state and background execution for stateful, long-running agents.
Promote changes through a repeatable pipeline:
GitHub commit
-> dependency and import validation
-> reproducible build
-> deployment
-> smoke test
-> schedule enablement
Tag the deployed code or image so you can identify the running revision. A rollback should restore a known application revision without deleting compatible checkpoints.
Before enabling the production schedule, verify:
- Required secrets are present.
- Checkpoints survive a runtime restart.
- Migrations have completed.
- Stable thread and run IDs are used.
- Retries are bounded.
- Concurrent execution is blocked.
- Database backups exist.
- Alerts reach an operator.
- Recovery has been tested with an intentional interruption.
- Rollback has been exercised.
A scheduled job is often simpler than an always-running process, but not always. Review the cron-versus-daemon tradeoffs for AI agents before fixing the runtime model.
Conclusion¶
Reliable LangGraph deployment starts with explicit operational decisions. Package one clear graph entry point. Lock dependencies. Inject secrets at runtime. Persist checkpoints outside the process. Use stable thread and run identifiers. Make every external side effect idempotent. Then schedule the job with overlap protection, logs, alerts, and a tested recovery path.
LangSmith Deployment can provide the managed Agent Server model. A standalone deployment gives you more infrastructure control and more operational responsibility. Other job-focused platforms, including HollowHost, can own parts of the surrounding build, scheduling, secret, and execution layer. Whichever runtime you choose, keep the graph portable and make failure recovery part of the initial design—not a patch after the first interrupted production run.