LangSmith Self-Hosted v0.15 and later can run Fleet as a standalone Helm-managed deployment (not reliant on the LangSmith Deployments control plane). If you previously enabled Fleet with the legacy backend.agentBootstrap and config.agentBuilder settings, migrate the Fleet database before switching traffic so existing assistants, threads, checkpoints, and schedules are preserved.
If the legacy agent-builder deployment already uses an external Postgres database, you do not need to copy data. Point standalone Fleet at the same external Postgres database, verify the assistants in the UI, and then clean up the legacy deployment.
Migration strategy
Use a maintenance window and migrate Fleet's LangGraph Postgres database with pg_dump and pg_restore. First enable standalone Fleet with Helm while preventing the legacy bootstrap job from deleting the old agent-builder deployment. Then copy the legacy Fleet database into the standalone Fleet database, verify the assistants in the UI, and clean up the legacy deployment.
This guide migrates Postgres data only. You do not need to migrate Redis data; Redis is used for cache, pub/sub, and in-flight work. Pause Fleet usage during the migration to avoid losing in-flight runs or writes that happen after the dump starts.
The standalone Fleet deployment requires LangSmith Self-Hosted v0.15 or later.
Prerequisites
Access to the Kubernetes namespace where LangSmith is installed.
Access to the legacy Fleet Postgres database.
A target Postgres database for standalone Fleet. This can be the bundled database created by the Helm chart or an external database.
pg_dumpavailable in a pod or admin host that can reach the legacy Fleet database.pg_restoreavailable in a pod or admin host that can reach the standalone Fleet database.The existing Fleet encryption key, usually
config.agentBuilder.encryptionKeyor theagent_builder_encryption_keykey in your LangSmith secret.
Before deleting the legacy agent-builder deployment, confirm that you have either completed the database migration or have a separate backup of the legacy Fleet database. Deleting the legacy deployment from the LangSmith Deployments UI may remove the database resources used by that deployment.
Migrate Fleet
By default, standalone Fleet creates and uses a bundled Postgres database from the Helm chart. This bundled database works with the dump and restore migration below.
During this process, you want to avoid any new runs of Fleet as they may be lost while the migration is going on. Schedule a maintenance window with your organization.
Update your values file to enable standalone Fleet. Keep the existing
backend.agentBootstrapandconfig.agentBuildervalues unchanged during this first upgrade. You will disable them after verifying standalone Fleet.
fleet:
enabled: true
# Use the same value as the legacy config.agentBuilder.encryptionKey.
# Prefer config.existingSecretName with agent_builder_encryption_key for production.
encryptionKey: "<existing-agent-builder-encryption-key>"
fleetToolServer:
enabled: true
fleetTriggerServer:
enabled: true Optionally, configure standalone Fleet to use an external Postgres database instead of the bundled database. If the legacy agent-builder deployment already uses an external Postgres database, you can reuse that same database and skip the dump and restore step.
fleet:
postgres:
external:
enabled: true
existingSecretName: fleet-postgres-secret The external Postgres secret must contain a postgres_connection_url key:
apiVersion: v1
kind: Secret
metadata:
name: fleet-postgres-secret
namespace: <namespace>
stringData:
postgres_connection_url: "<standalone-fleet-postgres-uri>"Upgrade LangSmith with the updated values:
$ helm upgrade -i langsmith langchain/langsmith \
--values langsmith_config.yaml \
--version <version> \
-n <namespace> \
--wait \
--debugAfter the upgrade, the LangSmith Deployments UI should still show the legacy
agent-builderdeployment, and Kubernetes should show the standalone Fleet resources.
Confirm the standalone Fleet pods are running:
$ kubectl get pods -n <namespace> | grep standalone-fleet
langsmith-standalone-fleet-api-server-7cb8bdbf6f-rpql8 1/1 Running 0 2m17s
langsmith-standalone-fleet-postgres-0 1/1 Running 0 2m16s
langsmith-standalone-fleet-queue-55458f45c5-pl87t 1/1 Running 0 2m17s
langsmith-standalone-fleet-redis-0 1/1 Running 0 2m16s List candidate legacy Fleet secrets without printing any secret values. The legacy agent-builder LangSmith Deployment secret usually contains a POSTGRES_URI key and is named like <legacy-service-name>-secrets
$ kubectl get secrets -n <namespace> \
-o jsonpath='{range .items[?(@.data.POSTGRES_URI)]}{.metadata.name}{"\n"}{end}'
# Example output:
agent-builder-04a3f94584ec55a0aeea18a173f732a5-secretsRun the migration
If the legacy agent-builder deployment already used the same external Postgres database configured in fleet.postgres.external, skip this step and continue to Step 5.
Run the migration from a secure admin shell. Pass the script the old and new database client pod names and the old and new secret names. For chart-managed Postgres, the pod name is usually the Postgres StatefulSet pod. For external Postgres, use a pod or admin host that has pg_dump or pg_restore installed and can reach the database.
The legacy secret key is usually POSTGRES_URI. The standalone Fleet secret key is postgres_connection_url. If the legacy deployment used an external Postgres secret through POSTGRES_URI_CUSTOM, use that external secret and set OLD_URI_KEY to the key that contains the URI.
If pg_restore fails because standalone Fleet has active database connections, temporarily scale down the standalone Fleet api-server and queue deployments, rerun the restore, and then scale them back up or rerun the Helm upgrade.
export NAMESPACE="<namespace>"
export OLD_DB_POD="<legacy-fleet-postgres-or-client-pod>" # Example: lg-04a3f94584ec55a0aeea18a173f732a5-0
export NEW_DB_POD="<standalone-fleet-postgres-or-client-pod>" # Example: langsmith-standalone-fleet-postgres-0
export OLD_FLEET_POSTGRES_SECRET="<agent-builder-service-name>-secrets" # From previous get secret command above. Example: agent-builder-04a3f94584ec55a0aeea18a173f732a5-secrets
export NEW_FLEET_POSTGRES_SECRET="<release>-standalone-fleet-postgres" # Example: langsmith-standalone-fleet-postgres
# Override these only if your secrets use different key names.
export OLD_URI_KEY="POSTGRES_URI"
export NEW_URI_KEY="postgres_connection_url"
# The dump is copied between pods. Keep it until the migration is verified.
export DUMP_FILE="/tmp/fleet-standalone-migration.dump"
# Row-count query. Run before (old pod) and after (new pod), then compare the
# output. The new side may match or exceed the old, but never be lower.
export ROW_COUNT_SQL="
SELECT 'assistant', count(*) FROM assistant
UNION ALL SELECT 'assistant_versions', count(*) FROM assistant_versions
UNION ALL SELECT 'thread', count(*) FROM thread
UNION ALL SELECT 'thread_ttl', count(*) FROM thread_ttl
UNION ALL SELECT 'checkpoints', count(*) FROM checkpoints
UNION ALL SELECT 'checkpoint_blobs', count(*) FROM checkpoint_blobs
UNION ALL SELECT 'checkpoint_writes', count(*) FROM checkpoint_writes
UNION ALL SELECT 'checkpoint_delete_queue', count(*) FROM checkpoint_delete_queue
UNION ALL SELECT 'run', count(*) FROM run
UNION ALL SELECT 'store', count(*) FROM store
UNION ALL SELECT 'cron', count(*) FROM cron;"
read_secret_key() {
local secret_name="$1"
local key_name="$2"
kubectl get secret "$secret_name" -n "$NAMESPACE" \
-o "go-template={{ index .data \"$key_name\" | base64decode }}"
}
OLD_FLEET_POSTGRES_URI="$(read_secret_key "$OLD_FLEET_POSTGRES_SECRET" "$OLD_URI_KEY")"
NEW_FLEET_POSTGRES_URI="$(read_secret_key "$NEW_FLEET_POSTGRES_SECRET" "$NEW_URI_KEY")"
if [ -z "$OLD_FLEET_POSTGRES_URI" ] || [ -z "$NEW_FLEET_POSTGRES_URI" ]; then
echo "One or both Postgres URI secret keys are empty." >&2
exit 1
fi
dump_dir="$(dirname "$DUMP_FILE")"
dump_base="$(basename "$DUMP_FILE")"
# Commands to confirm the right utilities exist
kubectl exec -n "$NAMESPACE" "$OLD_DB_POD" -- sh -ceu 'command -v pg_dump >/dev/null'
kubectl exec -n "$NAMESPACE" "$NEW_DB_POD" -- sh -ceu 'command -v pg_restore >/dev/null'
kubectl exec -n "$NAMESPACE" "$OLD_DB_POD" -- rm -f "$DUMP_FILE"
kubectl exec -n "$NAMESPACE" "$NEW_DB_POD" -- rm -f "$DUMP_FILE"
# Row counts BEFORE migration (old pod)
echo "=== Row counts BEFORE migration (old pod) ==="
kubectl exec -n "$NAMESPACE" "$OLD_DB_POD" -- psql "$OLD_FLEET_POSTGRES_URI" -At -F'|' -c "$ROW_COUNT_SQL"
echo ""
# The commands below are the ones that do the pg_dump and pg_restore
# Create the dump file in the OLD pod
kubectl exec -n "$NAMESPACE" "$OLD_DB_POD" -- sh -ceu \
'pg_dump --format=custom --no-owner --no-acl --file="$1" "$2"' \
-- "$DUMP_FILE" "$OLD_FLEET_POSTGRES_URI"
# Move the dump file from OLD pod to NEW pod
kubectl exec -n "$NAMESPACE" "$OLD_DB_POD" -- tar cf - -C "$dump_dir" "$dump_base" \
| kubectl exec -i -n "$NAMESPACE" "$NEW_DB_POD" -- tar xf - -C "$dump_dir"
# Restore NEW pod's db from the file
kubectl exec -n "$NAMESPACE" "$NEW_DB_POD" -- sh -ceu \
'pg_restore --clean --if-exists --no-owner --no-acl --dbname="$1" "$2"' \
-- "$NEW_FLEET_POSTGRES_URI" "$DUMP_FILE"
# Row counts AFTER migration (new pod)
echo ""
echo "=== Row counts AFTER migration (new pod) ==="
kubectl exec -n "$NAMESPACE" "$NEW_DB_POD" -- psql "$NEW_FLEET_POSTGRES_URI" -At -F'|' -c "$ROW_COUNT_SQL"
echo ""
echo "Fleet database migration completed. Verify row counts and Fleet in the UI before deleting legacy resources."Verify your past Fleet Agents show up in the LangSmith UI
Open Fleet in the LangSmith UI and confirm the legacy Fleet assistants are visible through the standalone Fleet deployment. Open recent threads and run a low-risk assistant to confirm reads and writes work against the restored database.
Cleanup the old Fleet agent deployment
After you verify standalone Fleet and no longer need to roll back, delete the legacy agent-builder deployment from the LangSmith Deployments UI.
Delete the config map as well:
kubectl delete configmap "<release>-agent-builder-config" \
-n <namespace> \
--ignore-not-found Then disable the legacy backend.agentBootstrap and config.agentBuilder settings in your values file. This is to avoid the Deployment from coming back:
backend:
agentBootstrap:
enabled: false
config:
agentBuilder:
enabled: falseKeep the database dump or your managed database backup according to your retention policy.
Rollback
If validation fails before you delete the legacy deployment, disable fleet.enabled, re-enable the legacy config.agentBuilder and backend.agentBootstrap settings, and run helm upgrade again with your previous values. Any writes made to standalone Fleet after the restore will not be present in the legacy deployment unless you perform another database migration.
If you already deleted the legacy deployment or its config map, restore from the dump file or your managed database backup before rolling back.