How I Boost Development Productivity with VSCodeVim
Around early 2021, I started using Vim for VSCode.
The reason was simple: after switching to an HHKB keyboard, there were no dedicated arrow keys (you have to hold Fn with your pinky), so I naturally wanted to minimize arrow key usage when editing text. Additionally, the Control key on an HHKB sits where Caps Lock usually is, making it much easier to press Control. Influenced by these external factors, I started learning Vim and found that pairing it with VSCode worked really well. Here, I’d like to share some thoughts and tips for anyone interested. If you’re curious about the HHKB keyboard, you can also check out my previous post — HHKB HYBRID Type-S Electrostatic Capacitive Keyboard Review.
VSCodeVim
VSCodeVim is an extension for VSCode that lets developers use Vim keybindings and motions inside VSCode. Using standalone Vim requires spending a lot of time tweaking configurations, and I didn’t want to leave the VSCode ecosystem, so pairing it directly with VSCode felt much smoother. This is also why I don’t recommend using standalone Vim alone: while tools are just aids, VSCode’s navigation, terminal integration, extensions, autocompletion, and other features can all effectively boost productivity.
This extension integrates very well with VSCode, allowing you to configure custom shortcuts bound to internal VSCode commands. Below, I’ll share several setups I use frequently. Rather than a Vim tutorial, this is more of a share on how I integrate this extension with other features.
Note that this article is simply recommending the combination of Vim and VSCodeVim; I’m not hard-selling Vim or insisting that every developer must use it.
(This article contains many GIF files. There is currently no image zoom feature, so if an image is too small, please open it in a new tab.)
Go to definition
When tracing source code, you often look at a function and its implementation at the same time. With the gd and gf bindings, I can navigate to implementations directly in normal mode without having to move the mouse, or quickly peek at types via preview, which is extremely convenient.

Merge Conflict
When conflicts occur while merging a Pull Request, several options appear at the top right to help resolve them, allowing you to choose incoming, current, or both. Again, to keep all operations on the keyboard, I set up custom shortcuts for them.

Copy GitHub File URL
Suppose I find a file implementation in VSCode and want to share it with team members; navigating manually on GitHub would be too tedious. The GitLens extension actually already integrates this feature (gitlens.copyRemoteFileUrlFrom), so you can bind it to a shortcut. You can also configure it to open your browser and jump straight to the GitHub tab.

Quickly Prettify Code
I mapped the format document action to ff in normal mode, so simply pressing f twice immediately prettifies the file, which is very handy. Of course, you can also just enable “format on save”.
Git Blame
While Git Blame on GitHub is convenient, being able to do it inside VSCode is even better. GitLens already provides this functionality, so we just need to bind a shortcut to it. Like this, I can trace specific code using the keyboard, blaming step by step until I find the culprit. (I’m using my own project as an example, but it’s even more useful in collaborative team projects.)

Open File in Finder (revealFileInOS)
Sometimes it’s useful to jump directly to the file’s path in the OS to make adjustments, so I also mapped this to a Vim shortcut.

Splitting 2 Tabs Side-by-Side (or Top-and-Bottom)
If you have a 27-inch external monitor, placing tabs side-by-side when writing HTML and CSS simultaneously makes them easier to view and switch between. In VSCodeVim, you can achieve this with :vs or :sp. You can also switch between panes using <C-w> + arrow keys.

If you’re interested, feel free to refer to the JSON configuration below. Everyone has their own preferred keybindings, so feel free to modify it according to your needs.
"vim.normalModeKeyBindings": [
{
"before": [
"g", "l"
],
"commands": [
"cmake.build"
]
},
{
"before": [
"<leader>",
"q"
],
"commands": [
"workbench.action.openRecent"
]
},
{
"before": [
"g",
"f"
],
"commands": [
"editor.action.peekDefinition"
]
},
{
"before": [
"g",
"n"
],
"commands": [
"cmake.build"
]
},
{
"before": [
"<leader>",
"<leader>",
"c"
],
"commands": [
"merge-conflict.accept.current"
]
},
{
"before": [
"<leader>",
"o"
],
"commands": [
"gitlens.openFileOnRemoteFrom"
]
},
{
"before": [
"<leader>",
"<leader>",
"i"
],
"commands": [
"merge-conflict.accept.incoming"
]
},
{
"before": [
"<leader>",
"<leader>",
"b"
],
"commands": [
"merge-conflict.accept.both"
]
},
{
"before": [
"<leader>",
"s"
],
"commands": [
"workbench.action.quickOpenTerm"
]
},
{
"before": [
"<leader>",
"c"
],
"commands": [
"gitlens.copyRemoteFileUrlFrom"
]
},
{
"before": [
"<leader>",
"b"
],
"commands": [
"gitlens.toggleFileBlame"
]
},
{
"before": [
"<leader>",
"p"
],
"commands": [
"gitlens.openBlamePriorToChange"
]
},
{
"before": [
"<leader>",
"a"
],
"commands": [
"workbench.view.explorer"
]
},
{
"before": [
"<leader>",
"<leader>",
"r"
],
"commands": [
"revealFileInOS"
]
},
{
"before": [
"f",
"f"
],
"commands": [
"editor.action.formatDocument"
]
},
{
"before": [
"+",
"+"
],
"commands": [
"workbench.action.increaseViewSize"
]
},
{
"before": [
"-",
"-"
],
"commands": [
"workbench.action.decreaseViewSize"
]
}
]
Other Handy Tips
vitvatto select tag blocks: Selects the block enclosed by tags directly, such as code wrapped inside a<div>.- By extension,
cit,dit, etc., can all be used to modify or delete the content respectively.
- By extension,
dstto remove the outer tag: In frontend work, you often have a wrapperdivthat you suddenly don’t need anymore; this command removes it easily.csttto change tags, e.g., fromptodiv: This is my favorite command—it makes changing tags super fast.
.: Repeat the previous action.yssb: Surround the text block with().yiwciw: Delete / change a single word.cs"': Replace"with'.dgn: Delete the search match.
I won’t list every other Vim trick here. VSCodeVim also supports macro recording—for more complex operations, you can record a macro first and replay it to save keystrokes.
Related Posts
- When a Measure Becomes a Target: From the Window Tax to Pull Request Counts I once wrote a script to tally how many PRs I contributed in a quarter, how many reviews I left, and how many tickets I closed, hoping to use numbers to prove my output to my manager. My manager simply remarked that performance isn't just about output. Years later, I finally understood—when a measure becomes a target, it ceases to be a good measure. From the British window tax and the Hanoi rat bounty to evaluating developers by PR counts today, the underlying mechanism is exactly the same.
- Using Cloudflare Images for Image Storage and Transformation Putting an image on a webpage is the simplest task in frontend development. But doing it properly—including resizing, generating multiple formats, and withstanding heavy traffic—is actually an entire end-to-end solution. Eventually, I offloaded everything to Cloudflare Images, keeping only a single original image.
- Stop Using AWS Access Keys Access Keys are an easily overlooked security risk in AWS. By pairing OIDC with IAM Roles, GitHub Actions can securely operate AWS resources without storing any secrets.
- Database Primary Keys: AUTO_INCREMENT, UUID, and UUIDv7 Backend developers often face the choice of primary keys: should you use auto-increment or UUID? What about collisions? How does UUIDv7 compare to created_at + index in performance? Here are the design decisions and benchmark results from testing 20 million rows.