What is the serve operation
The.serve operation connects your local Cognee Python SDK to Cognee Cloud or another remote Cognee instance.
After cognee.serve() connects, SDK calls such as remember(), recall(), improve(), and forget() run against the remote instance instead of local storage. This lets the same Python code work with local Cognee during development and with a hosted or self-hosted Cognee backend in production.
cognee-cli serve --url <instance> --api-key <key> runs the same connection and saves it for later bare serve() calls; it does not start a backend. The Python function cognee.serve() connects the SDK client to a remote or local backend.
Where serve fits
- Use
serve()when you want SDK operations to target Cognee Cloud. - Use it when you want to connect to a self-hosted Cognee API server.
- Use it before Push when you want
push()to reuse saved or active remote credentials. - Use
disconnect()when you want the SDK to return to local execution. - Use syncing a local instance for a cloud-focused walkthrough of the same connection flow.
What happens under the hood
- Resolve connection settings - Cognee looks for an explicit URL/API key, then
COGNEE_SERVICE_URL/COGNEE_API_KEY, then a saved connection that has an API key. With none of these,serve()raisesCogneeConfigurationError; there is no interactive login. It then probes an authenticated endpoint on the instance, so a rejected API key raisesCogneeConfigurationErrorhere instead of failing on the first operation (see Connection resolution). - Create a remote client - the SDK stores a client that knows how to call the remote Cognee API.
- Route SDK operations remotely - supported high-level operations execute against the connected instance.
- Persist the connection - a successful connection’s URL and API key are saved and reused by a later bare
serve(), together with the tenant id the instance reports atGET /api/v1/users/me. The tenant lookup times out after 5 seconds and never fails the connection; the id only tags telemetry while connected (see Tenant lookup). - Disconnect on request -
cognee.disconnect()clears the active remote client and returns the SDK to local mode.
Reconnecting with saved credentials
Every successfulserve() saves its URL, API key and tenant id to ~/.cognee/cloud_credentials.json. When serve() is called without a url and without COGNEE_SERVICE_URL, Cognee reuses that saved connection, but only if it holds both a service URL and an API key. A connection made without a key (a local server with access control off) is not reused; pass its url again.
The SDK health-checks the saved URL and then probes an authenticated endpoint with the saved API key. If the instance responds and accepts the key, serve() connects. If the instance does not respond or rejects the key, serve() raises CogneeConfigurationError (name="ServeConfigurationError") naming the credentials file and the saved URL. It suggests deleting the file if the connection is stale.
Credentials files written by older releases still load; their Auth0 tokens and other unknown keys are ignored, but a tenant id saved by the old cloud login is kept and reused. When the saved connection has no tenant id, a successful reconnect looks it up and writes it back to the file; a failed lookup or write does not stop the connection.
Request timeouts
Remote calls are bounded so a stalled connection cannot hang your process indefinitely:- Ordinary operations (
remember(),recall(),improve(),add(),cognify(),search(),forget(),update(),datasets.list_data(),datasets.find_data(),datasets.sparql()) allow up to 600 seconds total per request, with connection failures surfacing after 30 seconds. The 600 second total gives long blocking server-side work — for examplecognify()over a large dataset — room to finish. - Archive uploads used by
push()have no total cap, and are instead bounded by 600 seconds of read inactivity. An upload plus its synchronous server-side import can legitimately outlast any fixed total, so the upload is cut off only when the server stops sending data.
These timeouts are fixed values in the remote client. There is no environment variable or
serve() parameter to change them. If a blocking cognify() run is likely to exceed 600 seconds, submit it as a background run and poll for status instead of holding the request open.Proxy environment variables
The remote client honours the standard proxy environment variables —HTTP_PROXY, HTTPS_PROXY, and NO_PROXY — so remote traffic follows the same egress path as Cognee’s httpx- and litellm-based clients. Previously the remote client ignored them and connected to the instance directly, which failed behind a corporate egress proxy (connection errors) or behind a credential proxy that substitutes the real API key only on requests routed through it (401 responses, for example from cognee push inside a Docker Sandbox).
This applies to every call made to the connected instance:
- Every remote operation —
remember(),recall(),improve(),forget(),add(),cognify(),search(),update(),datasets.list_data(),datasets.find_data(),datasets.sparql(), and the archive uploads used bypush()— shares one HTTP session, so they all go through the proxy. - The connect-time probes (
/healthand the authenticatedGET /api/v1/datasets) use that same session. A key rejected through the proxy — for example, a credential proxy that did not substitute the real key — therefore fails duringserve(). An instance the proxy cannot reach is treated like any unreachable instance:serve()logs a warning and connects, and the errors surface on your first operation.
NO_PROXY:
Like the timeouts, this is a fixed value in the remote client: there is no
serve() parameter and no Cognee setting to turn it off. The environment variables themselves are the only control — unset them, or use NO_PROXY, when you want traffic to bypass the proxy. Note also that a configured proxy sees this traffic, and may terminate TLS on it.Filenames for raw-text uploads
When you pass a raw string — or a list containing strings — toremember(), add(), or update() while connected, the remote client uploads it as a file named text_<md5_hash>.txt, where the hash is computed from that string’s UTF-8 bytes. Each string in a list gets its own hash-derived name. This matches the naming local ingestion already uses for nameless text (see Hash-based file storage, deduplication, and filename collisions), so the same text produces the same object name whether it is ingested locally or over a serve() connection.
File-like objects are unaffected: they keep uploading under their own name attribute, falling back to upload when they have none.
Because every string is uploaded as content, a file path passed as a string is uploaded as that path’s text, not as the file it points at. Local ingestion resolves "/path/to/document.pdf", "file://…", and "s3://…" to the file; the remote client does not. Pass an open file object when you want the file’s contents to cross the connection. The exceptions are remember()’s content_type="code" and content_type="skills", which are path-based by design — code specs are sent as strings for the server to clone or read itself, and skill directories are walked locally so each SKILL.md is uploaded by content.
Previously every raw-text upload was sent as
data.txt. Because the name was fixed, all text uploads for a tenant landed on one remote object, so concurrent adds raced each other against the server’s content-hash read-back and could fail with a FileContentHashingError 409. Content-derived names remove that collision.Like the timeouts, this filename is a fixed value in the remote client — there is no parameter to supply your own. If you have tooling or tests that assert the uploaded name is data.txt, update them to expect text_<md5_hash>.txt. The uploaded text content itself is unchanged.Connection modes
- Explicit credentials
- Environment variables
- Saved connection
- Local backend
Pass the URL and API key of your Cognee Cloud tenant or self-hosted server directly.
After serve connects
Supported SDK operations run on the connected remote instance.serve() changes where SDK operations execute. It does not copy local datasets to the remote instance by itself. Use Push to upload an already-built local graph, or run remember() while connected to ingest data directly into the remote instance.Examples and details
Cognee Cloud
Cognee Cloud
Self-hosted server
Self-hosted server
Return to local mode
Return to local mode