It’s Cybersecurity Awareness Month! Join our interactive training session, or learn about security and AI from 1Password experts.
Forum Discussion
chuckwolber
2 months agoNew Contributor
CLI Slow Performance
I have the 1Password desktop app installed and up to date on my macBook Pro, the `op` CLI is also installed, up to date, and working properly. All expected CLI queries work but they are surprisingly slow.
After a bunch of trial and error, it seems that it is making a round-trip online as part of every single CLI query. I added the --debug flag and I can see cache hits, but the round trip online is still occurring. Disabling the network interface causes all queries to fail.
Is it possible to get the 1Password CLI working fully offline to avoid all of this unnecessary round-trip business? Surely with the desktop app installed and CLI integration turned on, there has to be a way to make efficient (and offline) use of my 1Password vaults.
Otherwise automation tasks that require secrets are simply too cumbersome to handle with 1Password, and I will require a secondary solution. And in that case, I may as well give up on 1Password.
7 Replies
- jeremyschlatterNew Contributor
Will this ever get addressed? I've seen posts as far back as 4 years. 1Password Team, please help!
In case it's helpful to collect them, here are four from this forum, plus three more reports elsewhere on the internet:
CLI commands are very slow | 1Password Community
Why is the CLI so slow? Any tips? | 1Password Community"op read" is pretty slow, ~700ms per invocation | 1Password Community
CLI cache is either not working or not significantly reducing time to return a secret | 1Password Communityhttps://www.reddit.com/r/1Password/comments/w9owk7/1password_cli_v_260_is_still_slow/
https://github.com/jdx/mise/discussions/3542
https://x.com/JukkaSuomela/status/1845065798231973953 - jeremyschlatterNew Contributor
Could you share more details about the timing issues? How long are you waiting, and what setup are you using?
In my case, the wait time is somewhere around 800ms to 1s. This is true for any read operation, eg `op item get`, `op read`, and `op inject` all take at least this long for a cached read. (Uncached can be even longer.) I'm running this from the command line on my M4 Max MacBook Pro.
There are a number of things I have wanted to do with the 1password CLI, but this ~1s latency has been a dealbreaker for all of them.
I didn't realize until this thread that the CLI talks to the 1Password API even for cached reads. This seems like a candidate for unnecessary latency?Finally, we recently introduced a the https://developer.1password.com/docs/sdks for more performant requirements. Take a peek, this may help.
I just tried the Go and Python SDKs. Both took at least 800ms just to initialize the client, let alone read a secret.
- 1P_Phil
Moderator
Hi chuckwolber & supercoder ,
Thanks for writing in and sharing your concern.
Could you share more details about the timing issues? How long are you waiting, and what setup are you using? It’ll help us identify any bottlenecks and better understand what you’re trying to achieve.
A note about the CLI and Caches:
The 1Password CLI caches items on Mac and Linux systems (not available on Windows). What it does not cache is the authentication to unlock 1Password. You are seeing these calls. After that you'll see the cache being accessed. (learn more here)
Finally, we recently introduced a the 1Password SDK for more performant requirements. Take a peek, this may help.
Thanks!
Phil- chuckwolberNew Contributor
1P_Phil -
macBook Pro 16" running macOS Sequoia 15.6.1, desktop client version: 8.11.8, 81108040 on PRODUCTION channel, and CLI version 2.32.0 installed via homebrew.
Yes, I took a look at the SDK, it did not help. Every usage required at least a 1.2 second delay involving a round trip to the cloud. Pretty much a dealbreaker for a command line tool with a local data source (1P desktop client) available to it.
Regarding the native 1P CLI...
Without the `--cache` argument:
~$ time op items list > /dev/null real 0m4.302s user 0m0.122s sys 0m0.057sWith the `--cache` argument:
$ time op --cache items list > /dev/null real 0m0.986s user 0m0.119s sys 0m0.055sSomething simple like listing vaults (which should be instant):
$ time op vault list > /dev/null real 0m1.022s user 0m0.082s sys 0m0.037s $ time op --cache vault list > /dev/null real 0m1.103s user 0m0.083s sys 0m0.039sWith all network disabled:
$ time op --cache items list > /dev/null [ERROR] 2025/09/18 15:28:47 Get "https://my.1password.com/api/v2/account/keysets?__t=1758209327.444": dial tcp: lookup my.1password.com: no such host real 0m0.184s user 0m0.018s sys 0m0.025sAs far as I can tell, a network round trip is required no matter what, which adds a full second for every CLI call.
- jeremyschlatterNew Contributor
It's not just one network round trip. Using https://www.mitmproxy.org/ you can see that each CLI call makes multiple network round trips, in series. For a cached `op vault list`, it's two:
HTTPS GET my.1password.com /api/v2/overview?__t=1758759373.782 200 …plication/json 3.1k 115ms HTTPS GET my.1password.com /api/v3/account?__t=1758759374.203&attrs=tier 200 …plication/json 2.0k 125msFor a cached `op read` it's four, all in series:
HTTPS GET my.1password.com /api/v2/overview?__t=1758759627.806 200 …plication/json 3.1k 118ms HTTPS GET my.1password.com /api/v3/account?__t=1758759628.196&attrs=tier 200 …plication/json 2.0k 122ms HTTPS GET my.1password.com /api/v3/account?__t=1758759628.354&attrs=tier 200 …plication/json 2.0k 110ms HTTPS GET my.1password.com /api/v2/overview?__t=1758759628.490 200 …plication/json 3.1k 115msThe last two requests are exact duplicates of the first two, meaning the CLI could save two round trips per call to `op item read` just by keeping the results of `/api/v3/account` and `/api/v2/overview` in memory. It could save another round trip time by requesting both `/api/v3/account` and `/api/v2/overview` in parallel rather than in series.
I also experimented with scripting mitmproxy to cache all of these requests. This effectively eliminates the network delay. The good news is that this saves ~220-500ms per CLI call (a little over 100ms per roundtrip). The bad news is that CLI calls still take a little over 400ms, which is still slow for reading at most a few kilobytes of data that is sitting locally on my machine. I'm not sure what the remaining slowdown is. Could be network roundtrips done by the 1password desktop app rather than the CLI, or could be something else.
With network delay:$ hyperfine 'op vault list' Benchmark 1: op vault list Time (mean ± σ): 649.8 ms ± 9.1 ms [User: 76.1 ms, System: 26.4 ms] Range (min … max): 636.9 ms … 664.8 ms 10 runs $ hyperfine 'op read "op://Private/gmail.com/username"' Benchmark 1: op read "op://Private/gmail.com/username" Time (mean ± σ): 929.9 ms ± 17.6 ms [User: 159.6 ms, System: 49.6 ms] Range (min … max): 901.2 ms … 957.1 ms 10 runsWithout network delay:
$ HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 hyperfine 'op vault list' Benchmark 1: op vault list Time (mean ± σ): 414.0 ms ± 6.9 ms [User: 60.8 ms, System: 18.2 ms] Range (min … max): 397.4 ms … 423.2 ms 10 runs $ HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 hyperfine 'op read "op://Private/gmail.com/username"' Benchmark 1: op read "op://Private/gmail.com/username" Time (mean ± σ): 435.5 ms ± 7.6 ms [User: 100.5 ms, System: 31.1 ms] Range (min … max): 422.1 ms … 449.8 ms 10 runsIf you're interested in reproducing the mitmproxy caching, here is the script I used:
from mitmproxy import http from urllib.parse import urlparse, parse_qs, urlencode import json import time class OnePasswordCache: def __init__(self): self.cache = {} def get_cache_key(self, flow): """Generate cache key by removing __t parameter""" url = urlparse(flow.request.pretty_url) params = parse_qs(url.query) # Remove __t parameter for cache key params.pop('__t', None) return ( url.scheme, url.netloc, url.path, urlencode(params), flow.request.headers["x-agilebits-session-id"], ) def request(self, flow: http.HTTPFlow): # Only cache GET requests to 1password API if (flow.request.method == "GET" and "1password.com/api/" in flow.request.pretty_url): cache_key = self.get_cache_key(flow) if cache_key in self.cache: # Serve from cache cached_response = self.cache[cache_key] # Create response from cache flow.response = http.Response.make( cached_response["status_code"], cached_response["content"], cached_response["headers"] ) # Add header to indicate cache hit flow.response.headers["X-Cache"] = "HIT" def response(self, flow: http.HTTPFlow): # Cache successful 1password API responses if (flow.request.method == "GET" and "1password.com/api/" in flow.request.pretty_url and flow.response.status_code == 200): cache_key = self.get_cache_key(flow) # Only cache if we didn't serve from cache if "X-Cache" not in flow.response.headers: self.cache[cache_key] = { "status_code": flow.response.status_code, "content": flow.response.content, "headers": dict(flow.response.headers) } addons = [OnePasswordCache()]Save as `cache_1password.py`, then run `mitmproxy -s cache_1password.py -p 8080`.
- supercoderNew Contributor
Will this ever get addressed? I've seen posts as far back as 4 years. 1Password Team, please help!