Resterm is a terminal client for working with HTTP, GraphQL, and gRPC services. No cloud sync, no signups, no heavy desktop app, no bullshit.
It pairs a Vim-like-style editor with a workspace explorer, response diff, history, profiler and scripting so you can iterate on requests without leaving the keyboard (no mouse support is a feature here).
.http / .rest files, supports recursion and keeps request lists in sync as you edit.Ctrl+F), clipboard motions, and inline metadata completions (type @ for contextual hints).@global (environment-wide), @var file (document), @var request (per-call), plus compile-time constants (@const), captures, JavaScript hooks, and multi-step workflows with per-step expectations and overrides.@graphql, @variables, @query) and gRPC directives (@grpc, @grpc-descriptor, reflection, metadata).@ws steps, automatic transcripts and an interactive console for ad-hoc frames..http collections from the CLI.Ctrl+Enter on a URL or curl block).@profile to benchmark endpoints and render histograms right inside the TUI.@trace to enable request tracing.@workflow + @step), override per-step variables, and review aggregated results in History.@compare directives or the global --compare flag + g+c shortcut so you can run the same request across diffrent envs. (dev/stage/prod etc.)If you just want to hit an API right now, you don’t need any files.
# In a project directory (no files required)
resterm
# Or explicitly point to a workspace
resterm --workspace path/to/project
Tab if needed).i or a and type a simple request, for example: GET https://httpbin.org/status/204
Ctrl+Enter to send the request.Tab / Shift+Tab - cycle focus between sidebar, editor, and response.g+p - jump directly to the response pane.g+i - jump back to the editor.That’s enough to be productive: open Resterm, type a URL, hit Ctrl+Enter, see the response.
If you work with .http / .rest files, Resterm will discover and use them.
.http / .rest files_examples/ in this repo for samples).resterm
# or
resterm --workspace path/to/project
.http / .rest files.Ctrl+Enter to send it.### Status check
# @name status
GET https://httpbin.org/status/204
User-Agent: resterm
### Authenticated echo
# @name bearerEcho
# @auth bearer {{auth.token}}
GET https://httpbin.org/bearer
Accept: application/json
A few keys that make Resterm feel “native” quickly:
Tab / Shift+Tab - move focus between sidebar, editor, and response.g+r - jump to Requests (sidebar).g+i - jump to Editor.g+p - jump to Response.g+h / g+l - adjust layout:
g+v / g+s - toggle response pane between inline and stacked layout.g+1, g+2, g+3 + minimize/restore sidebar, editor, response.g+z / g+Z - zoom the focused pane / clear zoom.Environments & globals
Ctrl+E - switch environments.Ctrl+G - inspect captured globals.Working with responses
Ctrl+V / Ctrl+U - split the response pane for side-by-side comparison.Ctrl+Shift+C or g y - copy the entire Pretty/Raw/Headers tab[!TIP]
If you only remember three shortcuts...
-Ctrl+Enter- send request
-Tab/Shift+Tab- switch panes
-g+p- jump to response
Drop a curl command into the editor and press Ctrl+Enter anywhere inside to turn it into a structured request. Resterm understands common flags (-X, -H, --data*, --json, --url, --user, --compressed, -F/--form, etc.), merges repeated data segments, and respects multipart uploads.
curl \
--compressed \
--url "https://httpbin.org/post?source=resterm&case=multipart" \
--request POST \
-H "Accept: application/json" \
-H "X-Client: resterm-dev" \
--user resterm:test123 \
-F file=@README.md \
--form-string memo='Testing resterm inline curl
with multiline value' \
--form-string meta='{"env":"test","attempt":1}'
If you copied the command from a shell, prefixes like sudo or $ are ignored automatically. Resterm loads the file attachment, preserves multiline form fields, and applies compression/auth headers without extra tweaks.
resterm.env.json (or legacy rest-client.env.json) discovered in the file directory, workspace root, or current working directory. Explicit dotenv files (.env, .env.*, *.env) are supported via --env-file only; we derive the environment name from a workspace entry, then the file stem, falling back to default for bare .env files. Important: Dotenv loading is single-workspace for now. Use JSON when you need multiple environments in one file.--workspace, --file, --env, --env-file, --timeout, --insecure, --follow, --proxy, --recursive, --from-openapi, --http-out, --openapi-base-var, --openapi-resolve-refs, --openapi-include-deprecated, --openapi-server-index.$HOME/Library/Application Support/resterm, %APPDATA%\resterm, or $HOME/.config/resterm (override with RESTERM_CONFIG_DIR)..toml or .json files under ~/.config/resterm/themes (override with RESTERM_THEMES_DIR) and switch them at runtime with Ctrl+Alt+T (or chord g then t).@workflow + @step blocks to build repeatable scenarios that run inside the TUI.expect.status, expect.statuscode) and pass data between steps via vars.request.* and vars.workflow.* namespaces.docs/resterm.md for the full reference and _examples/workflows.http for a runnable sample workflow.Try
_examples/compare.httpto see@comparedirectives and theg+cshortcut in action (pair it withresterm --compare dev,stage,prodfor instant multi-environment sweeps).
Modern API work rarely stops at a single environment, so Resterm bakes in a compare workflow that takes seconds to use:
# @compare dev stage prod base=stage to any request (or launch the app with --compare dev,stage,prod --compare-base stage).g+c (or Enter if you mapped the command) to send the current request to every listed environment. Resterm flips into a split view automatically so you can watch progress live.Enter and the primary pane shows that environment, the secondary pane pins the baseline and you land in the Diff tab so Pretty/Raw/Headers all reflect selected ↔ baseline.For more info. about compare runs, see docs/resterm.md#compare-runs.
# @trace metadata to a request. Budgets use phase<=duration syntax (for example dns<=50ms total<=300ms tolerance=25ms). Supported phases mirror the HTTP client hooks: dns, connect, tls, request_headers, request_body, ttfb, transfer, and total.Ctrl+Alt+L (or the g+t chord) and exit via the standard tab navigation.trace binding (trace.enabled(), trace.phases(), trace.breaches(), trace.withinBudget(), etc.), making CI assertions straightforward._examples/trace.http contains two runnable requests (one within budget, one intentionally breaching) for quick experimentation.RESTERM_TRACE_OTEL_ENDPOINT (or --trace-otel-endpoint) is set. Optional extras: RESTERM_TRACE_OTEL_INSECURE / --trace-otel-insecure, RESTERM_TRACE_OTEL_SERVICE / --trace-otel-service, RESTERM_TRACE_OTEL_TIMEOUT, and RESTERM_TRACE_OTEL_HEADERS.Deep dive into budgets, keyboard shortcuts, and trace scripting in docs/resterm.md#timeline--tracing.
Resterm can translate an OpenAPI 3 specification into a .http collection directly from the CLI.
resterm \
--from-openapi openapi-test.yml \
--http-out openapi-test.http \
--openapi-base-var apiBase \
--openapi-resolve-refs \
--openapi-server-index 1
--from-openapi points at the source spec, --http-out controls the generated .http file (defaults to <spec>.http when omitted).--openapi-base-var overrides the variable name injected for the base URL (falls back to baseUrl).--openapi-resolve-refs enables kin-openapi's $ref resolution before generation.--openapi-include-deprecated keeps deprecated operations that are skipped by default.--openapi-server-index picks which server entry (0-based) should populate the base URL if multiple servers are defined.The repository ships with openapi-specs.yml, an intentionally full-featured spec that covers array/object query parameters, callbacks, and unsupported constructs (for example OpenID Connect). Those unsupported pieces surface as Warning: lines within the generated header comment so you can verify warning handling end-to-end.
[!NOTE]
Resterm relies onkin-openapi, which currently supports OpenAPI documents up to v3.0.1. Work on v3.1 support is tracked in getkin/kin-openapi#1102.
More about OpenAPI importer and available flags in docs/resterm.md#importing-openapi-specs.
Streaming requests are first-class citizens in Resterm. Enable the Stream response tab to watch events in real time. See docs/resterm.md#streaming-sse--websocket for the complete directive list.
Annotate any HTTP request with # @sse to keep the connection open and capture events:
### Notification feed
# @name streamNotifications
# @sse duration=1m idle=5s max-events=50
GET https://api.example.com/notifications
Accept: text/event-stream
@sse accepts:
duration / timeout total session timeout before Resterm aborts the stream.idle / idle-timeout maximum gap between events before the stream is closed.max-events stop after N events (Resterm still records the transcript).max-bytes / limit-bytes cap downloaded payload size.The Pretty/Raw/Headers tabs collapse into a JSON transcript when a stream finishes and the history entry exposes a summary (events, bytes, reason). More SSE options and transcript fields live in docs/resterm.md#server-sent-events-sse.
Switch any request to WebSocket mode with # @websocket and describe scripted steps with # @ws lines:
### Chat handshake
# @name websocketChat
# @websocket timeout=10s receive-timeout=5s subprotocols=chat.v2,json
# @ws send {"type":"hello"}
# @ws wait 1s
# @ws send-json {"type":"message","text":"Hi"}
# @ws close 1000 "client done"
wss://chat.example.com/stream
or if you prefer just to open websocket connection:
### Chat
# @name websocketChat
# @websocket
ws://chat.example.com/stream
WebSocket options mirror runtime controls:
timeout - handshake deadline.receive-timeout - idle receive window (0 keeps it open indefinitely).max-message-bytes - hard cap for inbound payloads.subprotocols - comma-separated list sent during the handshake.compression=<true|false> - explicitly enable or disable per-message compression.Each @ws directive emits a step:
send/send-json/send-base64/send-file send text, JSON, base64, or file payloads.ping / pong transmit control frames.wait <duration> pauses before the next scripted action.close [code] [reason] ends the session with an optional status.The transcript records sender/receiver, opcode, sizes, close metadata and elapsed time. History entries keep the conversation for later review or scripted assertions. See docs/resterm.md#websockets-websocket-ws.
g+p, then switch to the Stream tab using the left/right arrow keys (or Ctrl+H / Ctrl+L). Follow events live, bookmark frames and scrub after the stream completes.Ctrl+I or g+r while the Stream tab is focused. Use F2 to cycle payload modes (text, JSON, base64, file), Ctrl+S (or Ctrl+Enter) to send, arrows to navigate history, Ctrl+P for ping, Ctrl+W to close and Ctrl+L to clear the buffer.stream API (stream.kind, stream.summary, stream.events, stream.onEvent()), enabling assertions on streaming workloads.Resterm ships with a default palette, but you can provide your own by dropping theme definitions into the themes directory mentioned above. Each theme can be written in TOML or JSON and only needs to override the parts you care about.
A ready-to-use sample lives in _examples/themes/aurora.toml. Point RESTERM_THEMES_DIR env var at that folder to try it immediately.
[metadata]
name = "Oceanic"
author = "You"
[styles.header_title]
foreground = "#5fd1ff"
bold = true
[colors]
pane_active_foreground = "#5fd1ff"
pane_border_focus_file = "#1f6feb"
Save the file as ~/.config/resterm/themes/oceanic.toml (or to your RESTERM_THEMES_DIR) and press Ctrl+Alt+T (or type g then t) inside Resterm to pick it as the default. The selected theme is persisted to settings.toml so it is restored on the next launch. The theming primer (directory layout, schema, and testing tips) lives in docs/resterm.md#theming.
Resterm looks for ${RESTERM_CONFIG_DIR}/bindings.toml first (and bindings.json second). Each entry maps an action ID to one or more bindings:
[bindings]
save_file = ["ctrl+shift+s"]
set_main_split_horizontal = ["g s", "ctrl+alt+s"]
send_request = ["ctrl+enter", "cmd+enter"]
+ (ctrl+shift+o), while chord steps are separated by spaces ("g s").send_request must stay single-step so it can fire while you type.The complete action catalog and a binding reference live in docs/resterm.md#custom-bindings.
Check out the sample in _examples/bindings/bindings.toml
The full reference, including request syntax, metadata, directive tables, scripting APIs, transport settings and advanced workflows, lives in docs/resterm.md.
Last modified 06 December 2025