[{"data":1,"prerenderedAt":648},["ShallowReactive",2],{"post-\u002Fblog\u002F2026\u002Fdevc-open-devcontainer-from-shell":3},{"id":4,"title":5,"body":6,"categories":635,"date":638,"description":639,"extension":640,"image":641,"meta":642,"navigation":113,"path":643,"seo":644,"stem":645,"tags":646,"__hash__":647},"blog\u002Fblog\u002F2026\u002Fdevc-open-devcontainer-from-shell.md","devc – Open a VS Code Dev Container Directly from the Shell",{"type":7,"value":8,"toc":620},"minimark",[9,13,16,21,36,44,61,64,71,80,149,156,160,196,204,208,214,219,235,239,248,331,346,350,358,390,399,403,486,490,540,551,555,569,604,608,616],[10,11,12],"p",{},"Moles are creatures of habit. We navigate our tunnels by feel, taking the same shortcuts every day without thinking about them. Until one day you realise you've been clicking through the same three VS Code menus every single time you want to open a project in a Dev Container – and it starts to feel like digging through concrete instead of soft earth.",[10,14,15],{},"The fix? A two-second shell command. That's all it takes.",[17,18,20],"h2",{"id":19},"the-problem","The Problem",[10,22,23,30,31,35],{},[24,25,29],"a",{"href":26,"rel":27},"https:\u002F\u002Fcode.visualstudio.com\u002Fdocs\u002Fdevcontainers\u002Fcontainers",[28],"nofollow","VS Code Dev Containers"," are fantastic. You define your full development environment in a ",[32,33,34],"code",{},".devcontainer\u002Fdevcontainer.json",", commit it to the repo, and anyone – including your future self after a full OS reinstall – gets the exact same toolchain, extensions, and settings.",[10,37,38,39,43],{},"The friction? Every time you want to ",[40,41,42],"em",{},"open"," a project in its container, you have to:",[45,46,47,51,58],"ol",{},[48,49,50],"li",{},"Open VS Code (or switch to it)",[48,52,53,54,57],{},"Hit ",[32,55,56],{},"F1"," → \"Dev Containers: Open Folder in Container...\" or press the appearing button in the bottom-right corner",[48,59,60],{},"Wait",[10,62,63],{},"If you live in the terminal (subways have terminals, tunnels are something alike) – and most moles do – this feels like a wrong turn every time.",[17,65,67,68],{"id":66},"the-solution-devc","The Solution: ",[32,69,70],{},"devc",[10,72,73,79],{},[24,74,77],{"href":75,"rel":76},"https:\u002F\u002Fgist.github.com\u002Fthe78mole\u002F02fc17c20a81113a28d26392d58218dc",[28],[32,78,70],{}," is a small bash script that collapses all of that into a single command:",[81,82,87],"pre",{"className":83,"code":84,"language":85,"meta":86,"style":86},"language-bash shiki shiki-themes github-light github-dark","# Open current directory in its Dev Container\ndevc .\n\n# Open a specific project by path\ndevc ~\u002Fprojects\u002Fmy-project\n\n# Show help\ndevc --help\n","bash","",[32,88,89,98,108,115,121,129,134,140],{"__ignoreMap":86},[90,91,94],"span",{"class":92,"line":93},"line",1,[90,95,97],{"class":96},"sJ8bj","# Open current directory in its Dev Container\n",[90,99,101,104],{"class":92,"line":100},2,[90,102,70],{"class":103},"sScJk",[90,105,107],{"class":106},"sZZnC"," .\n",[90,109,111],{"class":92,"line":110},3,[90,112,114],{"emptyLinePlaceholder":113},true,"\n",[90,116,118],{"class":92,"line":117},4,[90,119,120],{"class":96},"# Open a specific project by path\n",[90,122,124,126],{"class":92,"line":123},5,[90,125,70],{"class":103},[90,127,128],{"class":106}," ~\u002Fprojects\u002Fmy-project\n",[90,130,132],{"class":92,"line":131},6,[90,133,114],{"emptyLinePlaceholder":113},[90,135,137],{"class":92,"line":136},7,[90,138,139],{"class":96},"# Show help\n",[90,141,143,145],{"class":92,"line":142},8,[90,144,70],{"class":103},[90,146,148],{"class":147},"sj4cs"," --help\n",[10,150,151,152,155],{},"The container starts, and VS Code opens connected to it. If the directory doesn't contain a ",[32,153,154],{},".devcontainer"," config, the script warns you but continues – useful if you want to open any folder using the global devcontainer defaults.",[17,157,159],{"id":158},"how-it-works","How It Works",[10,161,162,163,165,166,169,170,175,176,179,180,183,184,187,188,191,192,195],{},"The script is deliberately simple – no dependencies beyond ",[32,164,85],{},", ",[32,167,168],{},"python3"," (for JSON parsing), and the ",[24,171,174],{"href":172,"rel":173},"https:\u002F\u002Fgithub.com\u002Fdevcontainers\u002Fcli",[28],"devcontainer CLI",". It locates the ",[32,177,178],{},"devcontainer.json"," in your project, reads the ",[32,181,182],{},"workspaceFolder"," from it (stripping ",[32,185,186],{},"\u002F\u002F comments"," first, since strict JSON parsers reject them), starts the container via ",[32,189,190],{},"devcontainer up",", and finally opens VS Code with the correct ",[32,193,194],{},"vscode-remote:\u002F\u002F"," URI built from the hex-encoded local path.",[10,197,198,199,203],{},"The full source is ",[24,200,202],{"href":75,"rel":201},[28],"on GitHub Gist",".",[17,205,207],{"id":206},"prerequisites","Prerequisites",[10,209,210,211,213],{},"Before ",[32,212,70],{}," can do its job, three things need to be in place: VS Code with the Dev Containers extension, Node.js (for the devcontainer CLI), and the CLI itself.",[215,216,218],"h3",{"id":217},"_1-vs-code-dev-containers-extension","1. VS Code + Dev Containers Extension",[10,220,221,222,227,228,231,232,234],{},"Install the ",[24,223,226],{"href":224,"rel":225},"https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=ms-vscode-remote.remote-containers",[28],"Dev Containers extension"," from the VS Code Marketplace. It provides the ",[32,229,230],{},"vscode-remote:\u002F\u002Fdev-container+..."," protocol handler that ",[32,233,70],{}," relies on to open VS Code connected to the container.",[215,236,238],{"id":237},"_2-nodejs-via-nvm","2. Node.js via NVM",[10,240,241,242,247],{},"The devcontainer CLI is an npm package, so you need Node.js. The cleanest way to manage Node.js versions on Linux and macOS is ",[24,243,246],{"href":244,"rel":245},"https:\u002F\u002Fgithub.com\u002Fnvm-sh\u002Fnvm",[28],"NVM (Node Version Manager)",":",[81,249,251],{"className":83,"code":250,"language":85,"meta":86,"style":86},"# Install NVM\ncurl -o- https:\u002F\u002Fraw.githubusercontent.com\u002Fnvm-sh\u002Fnvm\u002Fv0.40.3\u002Finstall.sh | bash\n\n# Reload your shell, then install the latest LTS release\nnvm install --lts\nnvm use --lts\n\n# Verify\nnode --version\nnpm --version\n",[32,252,253,258,276,280,285,296,305,309,314,323],{"__ignoreMap":86},[90,254,255],{"class":92,"line":93},[90,256,257],{"class":96},"# Install NVM\n",[90,259,260,263,266,269,273],{"class":92,"line":100},[90,261,262],{"class":103},"curl",[90,264,265],{"class":147}," -o-",[90,267,268],{"class":106}," https:\u002F\u002Fraw.githubusercontent.com\u002Fnvm-sh\u002Fnvm\u002Fv0.40.3\u002Finstall.sh",[90,270,272],{"class":271},"szBVR"," |",[90,274,275],{"class":103}," bash\n",[90,277,278],{"class":92,"line":110},[90,279,114],{"emptyLinePlaceholder":113},[90,281,282],{"class":92,"line":117},[90,283,284],{"class":96},"# Reload your shell, then install the latest LTS release\n",[90,286,287,290,293],{"class":92,"line":123},[90,288,289],{"class":103},"nvm",[90,291,292],{"class":106}," install",[90,294,295],{"class":147}," --lts\n",[90,297,298,300,303],{"class":92,"line":131},[90,299,289],{"class":103},[90,301,302],{"class":106}," use",[90,304,295],{"class":147},[90,306,307],{"class":92,"line":136},[90,308,114],{"emptyLinePlaceholder":113},[90,310,311],{"class":92,"line":142},[90,312,313],{"class":96},"# Verify\n",[90,315,317,320],{"class":92,"line":316},9,[90,318,319],{"class":103},"node",[90,321,322],{"class":147}," --version\n",[90,324,326,329],{"class":92,"line":325},10,[90,327,328],{"class":103},"npm",[90,330,322],{"class":147},[10,332,333,334,337,338,341,342,345],{},"NVM installs Node into ",[32,335,336],{},"~\u002F.nvm\u002F"," and doesn't require ",[32,339,340],{},"sudo",". You can switch between Node versions per-project using ",[32,343,344],{},".nvmrc"," files – handy when different projects need different runtimes.",[215,347,349],{"id":348},"_3-devcontainer-cli","3. devcontainer CLI",[10,351,352,353,357],{},"With Node.js in place, install the official ",[24,354,356],{"href":172,"rel":355},[28],"Dev Containers CLI"," globally:",[81,359,361],{"className":83,"code":360,"language":85,"meta":86,"style":86},"npm install -g @devcontainers\u002Fcli\n\n# Verify\ndevcontainer --version\n",[32,362,363,375,379,383],{"__ignoreMap":86},[90,364,365,367,369,372],{"class":92,"line":93},[90,366,328],{"class":103},[90,368,292],{"class":106},[90,370,371],{"class":147}," -g",[90,373,374],{"class":106}," @devcontainers\u002Fcli\n",[90,376,377],{"class":92,"line":100},[90,378,114],{"emptyLinePlaceholder":113},[90,380,381],{"class":92,"line":110},[90,382,313],{"class":96},[90,384,385,388],{"class":92,"line":117},[90,386,387],{"class":103},"devcontainer",[90,389,322],{"class":147},[10,391,392,393,395,396,398],{},"The CLI handles everything container-related: building the image, starting the container, and forwarding the workspace mount. ",[32,394,70],{}," just calls ",[32,397,190],{}," and then hands off to VS Code.",[215,400,402],{"id":401},"summary","Summary",[404,405,406,419],"table",{},[407,408,409],"thead",{},[410,411,412,416],"tr",{},[413,414,415],"th",{},"What",[413,417,418],{},"How",[420,421,422,435,444,454,464,473],"tbody",{},[410,423,424,428],{},[425,426,427],"td",{},"VS Code",[425,429,430],{},[24,431,434],{"href":432,"rel":433},"https:\u002F\u002Fcode.visualstudio.com\u002F",[28],"code.visualstudio.com",[410,436,437,439],{},[425,438,226],{},[425,440,441],{},[32,442,443],{},"code --install-extension ms-vscode-remote.remote-containers",[410,445,446,449],{},[425,447,448],{},"NVM",[425,450,451],{},[32,452,453],{},"curl -o- https:\u002F\u002Fraw.githubusercontent.com\u002Fnvm-sh\u002Fnvm\u002Fv0.40.3\u002Finstall.sh | bash",[410,455,456,459],{},[425,457,458],{},"Node.js LTS",[425,460,461],{},[32,462,463],{},"nvm install --lts",[410,465,466,468],{},[425,467,174],{},[425,469,470],{},[32,471,472],{},"npm install -g @devcontainers\u002Fcli",[410,474,475,483],{},[425,476,477,479,480],{},[32,478,168],{}," + ",[32,481,482],{},"xxd",[425,484,485],{},"Pre-installed on virtually all Linux\u002FmacOS systems",[17,487,489],{"id":488},"installation","Installation",[81,491,493],{"className":83,"code":492,"language":85,"meta":86,"style":86},"# Download the script\ncurl -fsSL https:\u002F\u002Fgist.github.com\u002Fthe78mole\u002F02fc17c20a81113a28d26392d58218dc\u002Fraw\u002Fdevc \\\n  -o \u002Fusr\u002Flocal\u002Fbin\u002Fdevc\n\n# Make it executable\nchmod +x \u002Fusr\u002Flocal\u002Fbin\u002Fdevc\n",[32,494,495,500,513,521,525,530],{"__ignoreMap":86},[90,496,497],{"class":92,"line":93},[90,498,499],{"class":96},"# Download the script\n",[90,501,502,504,507,510],{"class":92,"line":100},[90,503,262],{"class":103},[90,505,506],{"class":147}," -fsSL",[90,508,509],{"class":106}," https:\u002F\u002Fgist.github.com\u002Fthe78mole\u002F02fc17c20a81113a28d26392d58218dc\u002Fraw\u002Fdevc",[90,511,512],{"class":147}," \\\n",[90,514,515,518],{"class":92,"line":110},[90,516,517],{"class":147},"  -o",[90,519,520],{"class":106}," \u002Fusr\u002Flocal\u002Fbin\u002Fdevc\n",[90,522,523],{"class":92,"line":117},[90,524,114],{"emptyLinePlaceholder":113},[90,526,527],{"class":92,"line":123},[90,528,529],{"class":96},"# Make it executable\n",[90,531,532,535,538],{"class":92,"line":131},[90,533,534],{"class":103},"chmod",[90,536,537],{"class":106}," +x",[90,539,520],{"class":106},[10,541,542,543,547,548,203],{},"Or grab the ",[24,544,546],{"href":75,"rel":545},[28],"raw file from the Gist"," and drop it anywhere on your ",[32,549,550],{},"$PATH",[17,552,554],{"id":553},"why-not-just-use-the-vs-code-command","Why Not Just Use the VS Code Command?",[10,556,557,558,560,561,564,565,568],{},"You could. But ",[32,559,70],{}," fits into shell workflows. You can wrap it in aliases, call it from scripts, add it to a project's ",[32,562,563],{},"Makefile",", or use it with ",[32,566,567],{},"fzf"," to fuzzy-pick a project and open it in one keystroke:",[81,570,572],{"className":83,"code":571,"language":85,"meta":86,"style":86},"# Fuzzy-open any project in its Dev Container\nalias dv='devc \"$(find ~\u002Fprojects -maxdepth 2 -name devcontainer.json \\\n  | sed \"s|\u002F.devcontainer\u002Fdevcontainer.json||;s|\u002F.devcontainer.json||\" \\\n  | fzf)\"'\n",[32,573,574,579,594,599],{"__ignoreMap":86},[90,575,576],{"class":92,"line":93},[90,577,578],{"class":96},"# Fuzzy-open any project in its Dev Container\n",[90,580,581,584,588,591],{"class":92,"line":100},[90,582,583],{"class":271},"alias",[90,585,587],{"class":586},"sVt8B"," dv",[90,589,590],{"class":271},"=",[90,592,593],{"class":106},"'devc \"$(find ~\u002Fprojects -maxdepth 2 -name devcontainer.json \\\n",[90,595,596],{"class":92,"line":110},[90,597,598],{"class":106},"  | sed \"s|\u002F.devcontainer\u002Fdevcontainer.json||;s|\u002F.devcontainer.json||\" \\\n",[90,600,601],{"class":92,"line":117},[90,602,603],{"class":106},"  | fzf)\"'\n",[17,605,607],{"id":606},"the-gist","The Gist",[10,609,610,611,615],{},"The script lives at: ",[24,612,614],{"href":75,"rel":613},[28],"gist.github.com\u002Fthe78mole\u002F02fc17c20a81113a28d26392d58218dc"," – intentionally a single file, no installer, no package, no configuration. The tunnel is open.",[617,618,619],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":86,"searchDepth":100,"depth":100,"links":621},[622,623,625,626,632,633,634],{"id":19,"depth":100,"text":20},{"id":66,"depth":100,"text":624},"The Solution: devc",{"id":158,"depth":100,"text":159},{"id":206,"depth":100,"text":207,"children":627},[628,629,630,631],{"id":217,"depth":110,"text":218},{"id":237,"depth":110,"text":238},{"id":348,"depth":110,"text":349},{"id":401,"depth":110,"text":402},{"id":488,"depth":100,"text":489},{"id":553,"depth":100,"text":554},{"id":606,"depth":100,"text":607},[636,637],"Dev","Tools","2026-05-06","A tiny bash script that saves you from clicking through VS Code every time you want to open a project in a Dev Container – just type devc and go.","md","\u002Fimages\u002Fblog\u002F2026\u002F05\u002Fdevc-cover.jpeg",{},"\u002Fblog\u002F2026\u002Fdevc-open-devcontainer-from-shell",{"title":5,"description":639},"blog\u002F2026\u002Fdevc-open-devcontainer-from-shell",null,"mnUqrGHz8VPOCMkXcKzBZDHuxcCDMzn7FIbwe3tsoN0",1778331518261]