Just SFTP
Just SFTP: a minimal SFTP/FTP client for VS Code. One JSON config file, one activity-bar view, no magic.
- Browse SFTP/FTP servers in a side view — one folder per configured connection
- Edit remote files — click to open, save to upload back automatically
- Sync whole folders both ways (never deletes), with ignore globs and parallel connections
- Transfer only what changed — files identical at the destination (same size and modification time) can be skipped, per file or for the whole transfer, FileZilla-style
- Survive flaky connections — SSH keepalive, automatic reconnect mid-transfer with the interrupted file requeued, and one-click Retry Failed Files from History
- See what's where —
● badges in the file Explorer on files that exist remotely, plus right-click Upload to Remote
- Watch it happen — a live Transfers panel (FileZilla-style) and a per-operation History panel
Install
From the Marketplace: search Just SFTP in the Extensions view. Or from a .vsix: Extensions: Install from VSIX….
⚠️ Security warning — read this first
Credentials (passwords, key passphrases) are stored in plaintext in .vscode/just_sftp/config.json. That is the deliberate trade-off for simplicity. Add this line to your .gitignore before committing anything:
.vscode/just_sftp/
(One line covers everything the extension stores in your workspace: the config with credentials and the operation history.)
Usage
- Open the command palette (
Cmd+Shift+P / Ctrl+Shift+P) and run Just SFTP: Create Config. This creates .vscode/just_sftp/config.json with a template and opens it.
- Fill in one object per server. The file is a JSON array — add as many connections as you like:
[
{
"name": "my-server",
"protocol": "sftp",
"host": "example.com",
"port": 22,
"username": "deploy",
"password": "secret",
"privateKeyPath": "~/.ssh/id_ed25519",
"passphrase": "",
"remotePath": "/var/www/app",
"localPath": "./www",
"ignore": [".git/**", "node_modules/**"],
"parallel": 3,
"retries": 2,
"retryDelay": 1000
}
]
- Click the Just SFTP icon in the activity bar. Each configured connection shows up as a folder — expand it to connect and browse.
If two connections have overlapping localPaths (e.g. ./ and ./foobar), or overlapping remotePaths on the same host, a yellow warning appears in the Connections view: with overlapping mappings the same file has two counterparts, so syncs can duplicate content or overwrite each other. It's a warning, not an error — overlapping setups still work if that's what you intend.
Fields
| Field |
Required |
Notes |
name |
✅ |
Unique display name |
protocol |
✅ |
"sftp" or "ftp" |
host |
✅ |
Hostname or IP |
port |
|
Defaults to 22 (sftp) / 21 (ftp) |
username |
✅ |
|
password |
|
Plaintext — gitignore the file! |
privateKeyPath |
|
SFTP only; ~ is expanded |
passphrase |
|
For the private key |
remotePath |
|
Remote root for browsing and sync; defaults to / |
localPath |
|
Local sync folder, relative to the workspace or absolute; required for sync |
ignore |
|
Globs relative to the sync root, e.g. ".git/**" |
parallel |
|
Parallel connections for sync/download/upload, 1–10 (default 1) — used for both the listing phase and the transfers. Extra connections are opened per transfer batch; if the server refuses some, the transfer just runs with fewer. |
retries |
|
Retry attempts per failed file transfer, 0–10 (default 0). |
retryDelay |
|
Milliseconds to wait between retry attempts (default 1000). |
cacheTtl |
|
Seconds a cached remote listing stays fresh for the Explorer "present on remote" dots (default 86400 = 1 day). Transfers made through the extension update the cache immediately, so the TTL only matters for changes made outside it. |
Settings (VS Code settings, not the JSON config)
| Setting |
Default |
Notes |
justSftp.identicalFiles |
ask |
What to do with files that already exist at the destination with the same size and modification time. ask shows a per-file dialog — Skip / Transfer for that file, Transfer Only Changed / Transfer Everything to settle the rest of the transfer at once. skip and transfer answer permanently without asking. Comparison is size + mtime (checksums aren't available over SFTP/FTP); downloads stamp local files with the remote mtime so it keeps working across runs. |
justSftp.progressLocation |
notification |
Where transfer progress shows. notification is the bottom-right popup (percentage + Cancel button); statusBar hides the popup entirely — a spinner in the status bar instead, with live detail still in the Transfers panel (but no Cancel button). |
What you can do
- Browse: expand connections and folders in the tree. Refresh with the ↻ button.
- Edit remote files: click a file — it downloads to a temp mirror and opens. Saving uploads it back automatically. Last save wins; there is no conflict detection.
- Download / Upload: right-click a remote file or folder → Download to Local… — when the connection has a
localPath and the item is under remotePath, it downloads straight to the mirrored local location; otherwise a dialog asks where. Right-click a remote folder or connection → Upload Local Here….
- Sync: right-click a connection → Sync Remote → Local or Sync Local → Remote. Recursive copy from
remotePath ⇄ localPath, overwriting existing files at the destination. It never deletes files that only exist at the destination (no mirroring). ignore globs are skipped. Cancellable, with a summary at the end. Files identical at the destination trigger the justSftp.identicalFiles dialog (see Settings) so unchanged files can be skipped.
- Dropped connections heal themselves: SSH keepalive detects dead connections within seconds; the interrupted file goes back in the queue and the worker reconnects, so one drop no longer fails the rest of the transfer.
- Disconnect: right-click a connection.
- Remote presence dots: while a connection is active, files in the normal file Explorer that live under its
localPath get a ● badge when their mirrored path exists on the server. Powered by cached remote listings (cacheTtl); the extension never connects on its own just to decorate.
- Upload from the Explorer: right-click any file or folder in the file Explorer → Upload to Remote (Just SFTP). It must be under a configured
localPath; the mirrored remote path is used, and if several connections match you pick one.
- Live transfers: a Transfers panel between Connections and History shows operations in flight — each one expands to the files currently transferring (one per parallel connection) and a "N file(s) remaining" counter, FileZilla-style. Finished operations disappear from Transfers and land in History.
- Operation history: a History panel below Connections in the extension's side bar lists one entry per operation — a whole folder sync or folder upload/download is a single entry, as is each file transfer and each save-upload. Entries show status (success / partial / failed / cancelled) and file counts (including skipped-identical); clicking one opens its JSON record. History lives in
.vscode/just_sftp/history/ (one file per operation, capped at the 100 most recent). Clear it with the trash icon on the panel.
- Retry failed files: entries with failures show a ↻ button (and right-click → Retry Failed Files) that re-transfers exactly the files that failed — no need to re-run the whole operation.
Logs live in the Just SFTP output channel.
What it deliberately doesn't do
- Store credentials securely — they're plaintext in the config file (see SECURITY.md); gitignore
.vscode/just_sftp/ and prefer key auth.
- Conflict detection when editing remote files — last save wins.
- Delete anything during sync — it only copies and overwrites; destination-only files are never touched. A mirror mode may come later if there's demand.
- FTPS — FTP support is plain FTP (passive mode) for now; FTPS may come later.
Development & contributing
See CONTRIBUTING.md for dev setup, the Docker-backed e2e test suite (npm run test:e2e), and architecture notes. Security posture is documented in SECURITY.md.
License
MIT © Ravidhu Dissanayake