Self-hosting
Store agents locally or on infrastructure you control
Letta agents can run entirely on infrastructure you control, in two shapes:
- Local runtime: The CLI runs agents in-process. The desktop app uses a background App Server on your machine. In both cases, all agent state, including messages, memory, and provider connections, stays on-device, and no Letta account is required.
- Self-hosted App Server: Run the Letta App Server to host local agents on a central, always-on machine and expose them to client applications through the Agent SDK. Run messaging channels in a separate server process on the same machine.
-
Install the Letta CLI
npm install -g @letta-ai/letta-code -
Connect model providers
Connect the model providers you want your agents to use, for example a locally running Ollama server:
letta --backend local connect ollamaYou can also connect external API keys or other local inference servers:
letta --backend local connect anthropic --api-key "$ANTHROPIC_API_KEY"letta --backend local connect lmstudio --base-url http://127.0.0.1:1234/v1See Models for the full list of supported providers.
-
Run the Letta server
Start the App Server with the local backend:
letta server --backend local --listen ws://127.0.0.1:4500The process prints the base URL and channel URLs at startup. See the App Server quickstart for authentication and configuration options.
-
Add channels (optional)
To make your agents reachable through messaging platforms, start a separate local server process with one or more channels:
letta server --backend local --channels slackSee the channel-specific guides for setup instructions, e.g. Slack, Telegram, or Discord.
-
Connect via the SDK (optional)
Connect to the running server from your application with the Letta Agent SDK’s remote backend:
import { LettaAgentClient } from "@letta-ai/letta-agent-sdk";const client = new LettaAgentClient({backend: "remote",url: "http://127.0.0.1:4500",});See the Agent SDK section below for a full example.
-
Install the Letta CLI
npm install -g @letta-ai/letta-codeTo launch the Letta CLI, run:
lettaIf you’re running the Letta CLI interactively for the first time, a Tutor agent will be auto-created for you.
-
Connect to LLM providers
Use
/connectto connect external API keys, coding plans, and local inference servers. -
Navigate to your project
cd your-projectletta
-
Download and install the Letta app
Download for macOS -
Open the Letta app and connect models
Launch the app and select “Skip login” (this will store agents locally).
Click “Connect model providers” in the bottom-left menu to add external API keys, coding plans, or locally running model endpoints.
Model inference is a separate choice. If you connect a remote model provider, prompts still go to that provider. To keep inference local too, connect a local provider such as Ollama, LM Studio, or llama.cpp. See Local models for both local and cloud-hosted setup options.
Agent SDK
Section titled “Agent SDK”The Letta Agent SDK supports two backends for self-hosted setups:
- Local backend (
backend: "local"): The SDK starts App Server automatically as a subprocess on the current machine. Agent state and the execution environment stay on the machine running your code. Use this for development or single-machine deployments—no separate server process to manage. - Remote backend (
backend: "remote"): The SDK connects to an App Server you run as a separate service (letta server --listen). Agent state and the execution environment live on the App Server machine, so multiple clients can share the same agents and the server can run on different infrastructure than your application.
import { LettaAgentClient } from "@letta-ai/letta-agent-sdk";
const client = new LettaAgentClient({ backend: "local" });
const agentId = await client.createAgent({ persona: "You are Patch, a resident engineering teammate for this repository.",});
await using session = client.createSession(agentId, { cwd: process.cwd(),});
await session.send("Inspect this repository and write an onboarding memo.");
for await (const message of session.stream()) { if (message.type === "assistant") { console.log(message.content); }}Start an App Server on the machine that should hold agent state:
letta server --backend local --listen ws://127.0.0.1:4500Then connect to it from your application:
import { LettaAgentClient } from "@letta-ai/letta-agent-sdk";
const client = new LettaAgentClient({ backend: "remote", url: process.env.LETTA_APP_SERVER_URL ?? "http://127.0.0.1:4500", authToken: process.env.LETTA_APP_SERVER_TOKEN,});
const agentId = await client.createAgent({ persona: "You are Ops, a digital employee running in a shared workspace.",});
await using session = client.createSession(agentId, { cwd: "/workspace/project",});
await session.send("Prepare a morning handoff report for the workspace.");
for await (const message of session.stream()) { if (message.type === "assistant") { console.log(message.content); }}See the Agent SDK docs for full setup instructions and Deployment for production configurations.
For OpenAI-compatible clients, see the App Server quickstart.
Deployment
Section titled “Deployment”The App Server deployment repository contains one Dockerfile plus ready-to-use configuration for Docker Compose, Railway, and Fly.io. It runs App Server with the local backend, so agent state, memory, and tool execution stay on the deployed machine.
Docker Compose
Section titled “Docker Compose”git clone https://github.com/letta-ai/letta-app-server-deployment.gitcd letta-app-server-deploymentcp .env.example .envSet LETTA_APP_SERVER_TOKEN and at least one model provider key in .env, then start the service:
docker compose up --build -ddocker compose logs -fcurl http://127.0.0.1:4500/readyzThe Compose file exposes port 4500 and creates persistent volumes for /root/.letta and /workspace.
Railway
Section titled “Railway”- Fork the deployment repository.
- Create a Railway project from the fork. Railway detects its
Dockerfileandrailway.json. - Add
LETTA_APP_SERVER_TOKENand a model provider key, such asANTHROPIC_API_KEY, as Railway variables. - Add a persistent volume mounted at
/root/.letta. - Generate a public domain for the service.
Railway terminates TLS, forwards WebSocket connections to App Server, and checks /readyz during deploys.
Fly.io
Section titled “Fly.io”git clone https://github.com/letta-ai/letta-app-server-deployment.gitcd letta-app-server-deploymentfly launch --name your-letta-app-server --no-deployfly volumes create letta_state --region sjc --size 1
export LETTA_APP_SERVER_TOKEN="$(openssl rand -hex 32)"fly secrets set \ LETTA_APP_SERVER_TOKEN="$LETTA_APP_SERVER_TOKEN" \ ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY"fly deployThe included fly.toml mounts the volume at /root/.letta, exposes App Server through Fly’s HTTPS proxy, and checks /readyz.
Other container platforms
Section titled “Other container platforms”Deploy the repository anywhere that accepts a Dockerfile. Expose the container’s PORT (default 4500), persist /root/.letta, set LETTA_APP_SERVER_TOKEN and a model provider key, and route HTTPS or WSS traffic to the service. Use /readyz as the health check.
Connect your application
Section titled “Connect your application”import { LettaAgentClient } from "@letta-ai/letta-agent-sdk";
const client = new LettaAgentClient({ backend: "remote", url: process.env.LETTA_APP_SERVER_URL, authToken: process.env.LETTA_APP_SERVER_TOKEN,});App Server has shell and filesystem access on its host. Keep its token in your application’s backend or secret store rather than exposing it to browser clients. See App Server for protocol and authentication details.
Where local state is stored
Section titled “Where local state is stored”By default, local state is stored in:
~/.letta/lc-local-backendEach agent’s MemFS repository is stored under:
~/.letta/lc-local-backend/memfs/<agent-id>/memoryUse LETTA_LOCAL_BACKEND_DIR to isolate local state for a project or experiment:
export LETTA_LOCAL_BACKEND_DIR="$PWD/.letta-local"letta --backend local --new-agentAdd .letta-local/ to .gitignore if you create it inside a repository.
Troubleshooting
Section titled “Troubleshooting”My prompts are still going to a remote provider
Section titled “My prompts are still going to a remote provider”Local setup stores agent state locally, but inference follows the model provider you selected. Switch to an Ollama, LM Studio, or llama.cpp model to run inference locally.
My local model does not appear in /model
Section titled “My local model does not appear in /model”Make sure the local inference server is running, then reconnect the provider:
letta --backend local connect ollamaletta --backend local connect lmstudio --base-url http://127.0.0.1:1234/v1I want a clean local setup for testing
Section titled “I want a clean local setup for testing”Set LETTA_LOCAL_BACKEND_DIR to a temporary directory before launching Letta Code:
export LETTA_LOCAL_BACKEND_DIR="$(mktemp -d)"letta --backend local --new-agent