Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>FTP DeployNew to Visual Studio Code? Get it now.
FTP Deploy

FTP Deploy

Akshay Landage

|
4 installs
| (0) | Free
Incremental FTP/FTPS/SFTP deploy with multi-profile support, dry-run preview and on-demand snapshots.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

FTP Deploy

Incremental FTP/FTPS/SFTP deploy for VS Code, built around multiple servers as a first-class concern.

  • Profiles for every server you publish to, each with its own credentials, paths and file selection — switch or right-click to deploy to any of them.
  • Rules: a named pipeline of steps — run a build, back the server up, delete, upload — that runs end to end with one click.
  • Incremental by hash, not by timestamp, so only what genuinely changed goes over the wire.
  • Dry run everything first: the full plan, file by file, before anything moves.
  • Atomic uploads, size verification, and a manifest written per file so an interrupted run resumes cleanly.
  • Passwords and passphrases live in the OS keychain, never in the config.

Getting started

Nothing needs to be hand-written.

  1. Open the FTP Deploy icon in the activity bar.
  2. Click + New profile — a form covers every setting: protocol, host, port, credentials, key file, local and remote roots, include/exclude globs, and the mirror-delete switch.
  3. Test connection inside the form, before saving.
  4. Save — the profile is written to .vscode/ftp-deploy.json and the password goes to the OS keychain.
  5. Right-click the profile → Dry Run, then Deploy.

Repeat step 2 for every server. Right-click any profile to deploy to it directly, regardless of which one is active.

The config file stays readable and hand-editable — the editor writes through jsonc-parser, so your comments and formatting survive.

Profiles

A profile is one server. Names must be unique, because the name is the key for two separate things:

  • The stored credential. Namespaced by scope and profile name, so production in this project never reads production from another.
  • The manifest section. Each profile gets its own block of upload state. Two servers hold different state; a shared section would make a diff for one host reflect uploads made to another.

Mark a profile development, staging or production and the environment colours its badge everywhere it appears — the confirmation before a production deploy is the one you want to actually read.

Commands resolve their target in this order: right-click → active profile → defaultProfile → first profile.

Rules

A rule is a named pipeline: pick the files once, then list the steps to run on them. Running the rule executes every step in order with no further prompting — that is the whole point of it.

Add one from a profile → New rule. The editor has three parts: where it deploys, which files it acts on, and what it does to them.

Choosing the files

One selection per rule, applied to whichever side each step reads from.

  • Include files — the local folder as a tree, with the ticks showing what the globs really match, evaluated by the same matcher the deploy uses.
  • Exclude patterns — the raw glob lists, for anything a tree cannot express.
  • Server files — the live remote tree, browsed on demand. Ticking here edits the same lists. The bin icon deletes on the server immediately and is not part of the rule.

Every list carries the same toolbar: filter by name, Expand all, Collapse, Reload, Select all, Unselect all.

Ticking a folder writes folder/**; unticking one file adds just that path. Content-hashed names are generalised for you — untick main.1b26a9b7.js and the rule stores main.*.js, which still matches after the next build.

Steps

Step What it does
Run a command A shell command — your build — with its own working folder.
Back up Timestamped copy of the server files about to be replaced, saved to your disk, with a MANIFEST.txt receipt.
Upload Only files that changed (manifest diff) or Every matched file, always (override).
Delete remote files Only what this run backed up, or everything the selection matches.
Delete local files Removes the matched files from your disk.
Mirror deletes Removes remote files this profile uploaded that no longer exist locally.

Each step says what it will cost before you run it — an upload with no backup step above it says so, and a delete paired with a backup says that the server only loses files already saved to your disk.

Any step can narrow the rule's selection further under Files for this step: a folder tree of exactly what that step will touch, where unticking affects that step alone. "Back up everything, then delete all of it except web.config" is two ticks.

Presets

One click each: Upload changed · Upload with override · Back up server · Back up then upload · Back up, delete, upload · Build, back up, delete, upload · Back up local then delete local · Upload + mirror deletes.

The rule that keeps "back up then delete" safe

Delete local files is rejected unless a back up or upload step comes before it — enforced in the editor, again before the file is written, and again when the config loads. Order matters: deleteLocal then backup is refused.

At run time it goes further. Each step records which files it verified landed on the server (size-checked, manifest-recorded). deleteLocal deletes only those files. A file whose upload failed is kept and logged:

kept src/ui/app.js — not confirmed on the server this run

So a half-failed transfer can never take your local copy with it.

Running

  • Dry Run Rule — every step, what it would touch, destructive ones flagged.
  • Run Rule — executes the pipeline, with live progress per file.
  • Run All Rules — every enabled rule in order.

Rules that delete always confirm first, even inside Run All, and the confirmation lists the actual steps. Disable a rule to keep it but skip it in Run All.

Where profiles and rules are stored

By default they live in the folder that uses them, at .vscode/ftp-deploy.json — committed with the project, reviewed with the project.

If you deploy the same handful of servers from a dozen different folders, keep one set for the whole machine instead. Run FTP Deploy: Config Location (This Folder or This Machine) and pick This machine:

This folder This machine
Profiles and rules .vscode/ftp-deploy.json ~/.ftp-deploy/ftp-deploy.json
Upload state .vscode/.ftp-deploy-manifest.json ~/.ftp-deploy/manifest.json
Passwords keychain, per folder keychain, once per machine
Active profile, run history per folder shared

Switching offers to copy the current folder's config across, and leaves the other file untouched — switching back loses nothing. Passwords are namespaced per scope, so set them once after a first switch.

Rules stored for the machine should use absolute local paths: there is no one folder for a relative path to resolve against, and they may run in a window with no folder open at all.

How change detection works

Deploy compares local files against the manifest, not against the server.

FTP exposes no file hash, and its timestamps drift with server timezone and DST, so remote metadata cannot reliably answer "did this change?". Instead, every confirmed upload is recorded as sha256 + size + timestamp. The next run hashes locally and uploads only what differs.

Commit .vscode/.ftp-deploy-manifest.json to git so every machine deploys the same incremental set. Delete a profile's section — or run Reset Manifest — to force a full re-upload.

Backups

A Back up step copies files into a timestamped folder on your disk — 2026-08-17_1430/ — before anything overwrites or deletes them. It can copy either side: the server files about to be replaced, or your local files.

  • The folder it writes into comes from the step, or from localBackupRoot when the step leaves it blank.
  • snapshotFolderFormat names the timestamped subfolder.
  • snapshotWriteReceipt adds a MANIFEST.txt listing every file's hash and size, so a backup can be verified or restored without this extension.

Backups are always complete, never incremental, and are never written to the server. Nothing prunes them — delete old folders yourself.

Safety

  • Dry run first. confirmBeforeDeploy (default on) shows the plan, then asks for a modal confirmation.
  • Atomic writes. Every file uploads to <name>.part and is renamed into place. A dropped connection leaves an orphaned .part, never a truncated web.config serving 500s.
  • Size verification after each transfer, before the manifest records it.
  • Manifest written per file, not at the end — an interrupted run leaves a manifest describing exactly what actually landed, and the next run resumes.
  • Deletes are opt-in. mirrorDeletes is false by default. Files gone locally are reported as orphans and left alone.
  • Excludes always beat includes, plus a built-in default exclude list (node_modules, .git, dist, .env, *.log…).
  • Secrets live in the OS keychain, never in the config file.

Settings

FTP Deploy: Open Settings, or search ftpDeploy in the Settings UI. Per-server details live in profiles; these are the behaviour knobs.

Setting Default What it does
configScope workspace workspace = this folder, global = ~/.ftp-deploy/ for the whole machine.
configPath .vscode/ftp-deploy.json Where profiles live, in workspace scope.
manifestPath .vscode/.ftp-deploy-manifest.json Where upload state lives.
showStatusBar true Active profile in the status bar.
confirmBeforeDeploy true Modal confirmation before transferring.
openPlanInEditor false Also open the plan as a text document.
verifySizeAfterUpload true Check remote byte count before recording.
confirmDeletes true Separate second prompt for remote deletions.
retries 3 Per-file attempts; backoff 2s/4s/8s.
commandTimeoutMs 600000 How long a command step may run.
listConcurrency 4 Connections the rule editor lists server folders over. 1 if the host refuses extra sessions.
connectTimeoutMs 20000 Connection timeout.
maxFileSizeMb 0 Skip files over this size. 0 = no limit.
useDefaultExcludes true Apply the global exclude list.
defaultExcludes (11 globs) Excluded from every profile. Fully editable.
followSymlinks false Follow links when scanning.
localBackupRoot (empty) Default folder for back up steps that name none.
snapshotFolderFormat YYYY-MM-DD_HHmm Name of the timestamped backup subfolder.
snapshotWriteReceipt true Write MANIFEST.txt into each backup.

Config reference

For hand-editing .vscode/ftp-deploy.json. It accepts // and /* */ comments.

Key Required Notes
name ✅ Unique. Keys the credential and manifest section.
protocol ✅ sftp | ftp | ftps
host / username ✅
remoteRoot ✅ Absolute remote path.
port Defaults to 22 (sftp) or 21.
privateKeyPath SFTP only. Passphrase goes in the keychain.
localRoot Workspace-relative. Defaults to the workspace root.
include / exclude Globs. Include builds the set, exclude subtracts.
environment development | staging | production. Colours the badge.
mirrorDeletes Default false.
secureRejectUnauthorized ftps only. Leave true unless you know why.

Known limits

  • Uploads are sequential. Both FTP and SFTP clients drive a single channel, so parallel calls on one connection corrupt each other. Browsing the server in the rule editor already uses a pool of connections (listConcurrency); the same trick would work for uploads and has not been done yet.
  • Depth is not parallelisable. A folder must be listed before its children are known, so a deep chain of single folders is one round trip at a time however many connections are open. Wide trees — a resources folder per locale — are where a pool pays.
  • No scheduling. An extension only runs while VS Code is open; there is no background activation.
  • No restore/download yet.

Building from source

npm install
npm run package     # runs the tests, then builds ftp-deploy-<version>.vsix
code --install-extension ftp-deploy-1.0.0.vsix --force

Reload the window afterwards. F5 launches an Extension Development Host instead, and npm run watch rebuilds on save.

src/
  config/     types, settings, JSONC read + write, SecretStorage
  core/       scanner (globs), hash, manifest, plan, rule engine
  transport/  Transport interface, sftp + ftp impls, atomicPut, retry
  commands/   one file per user-facing action
  ui/         dashboard, profile and rule editors, deployment panel

core/ and transport/ are free of vscode imports on purpose — that is what keeps a future CLI possible.

License

MIT

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft