User guide
A practical guide to using VSCodroid -- the full VS Code IDE running natively on your Android device.
First Launch
What Happens on First Open
- Install. Download from the Play Store or GitHub Releases. The core download is roughly 270 MB, and you need about 738 MB free for the extraction that follows.
- Binary extraction -- On first launch, VSCodroid extracts bundled tools (Node.js, Python, Git, Bash, and others) to internal storage. About 603 MB lands on disk, unpacked one file at a time behind a progress bar, so allow minutes rather than seconds on a slower device. The ~738 MB above is that payload plus the working room setup insists on before it will start. It happens on the first launch and again after every app update, because the extraction is keyed on the app version rather than on what is already unpacked. An update needs far less free space than a fresh install (the app credits what it already holds, so roughly 230 MB rather than 738 MB), but it does re-copy the files and it does take minutes. A first run that is interrupted and retried on the same version is the one case that does not start over: files already the right size are left alone.
- Language Picker -- A prompt asks "What do you code in?" with options for Ruby and Java. It comes back at each launch until you answer it with Continue or Skip, and your answer is not final: touch and hold the app icon and pick Manage toolchains to add or remove them later. Whatever you select downloads there on the setup screen, one at a time; a download that fails is skipped and the rest continue. Skip goes straight to the editor.
- Ready -- The VS Code editor loads with terminal, file explorer, and all bundled tools available immediately.
Default File Locations
| Item | Path |
|---|---|
| Projects folder | ~/projects/ |
| Settings and data | ~/.vscodroid/ |
| SSH keys | ~/.ssh/ |
All files are stored in the app's private sandbox. No root access is required.
Editor Basics
VSCodroid is VS Code. If you have used VS Code on desktop, everything works the same way.
Opening Files and Folders
- Use File > Open Folder or the Explorer sidebar for projects inside the app.
Typing a path such as
/storage/emulated/0/...or/sdcard/...into that dialog reaches Documents, Downloads or an SD card, but VSCodroid holds no storage permission, so Android shows it the folders there and hides every file another app saved in them. Such a folder opens with its subfolders and none of those files; the editor then says so in a dialog, once per folder each time its server starts rather than on every reload, and offers the route below. - For a folder anywhere else on the device, run VSCodroid: Open Folder from
Device: tap the remote indicator at the left end of the status bar, tap the
button in the empty Explorer, or use the Command Palette. It opens Android's
folder picker; pick the folder and allow access, and the files other apps
saved in it show as well, apart from what the copy below leaves out. Android
grants access one folder at a time, and not to the top of the storage or of an
SD card, nor to the Download or Android folder itself, so pick a folder inside
those. Nothing in
Android/data,Android/obborAndroid/sandboxcan be granted, since Android keeps each app's folder there to that app. A USB drive can be granted whole. VSCodroid: Open Recent Folder, in the same menu, lists the folders you have granted, with Browse device... at the end to add another. - A device folder is edited as a copy inside the app. The copy is read from the
device when you open the folder, and each save is written back to the device
as you make it. It leaves out files the device folder reports as over 50 MB,
and the directories
.git,node_modules,.gradle,.idea,venv,.envand__pycache__are neither read in nor written back, so a git repository opened this way has no history here. Changes another app makes while the folder is open do not reach the editor until you open the folder again. If you save a file that another app changed since you opened the folder or last saved that file, the other app's version is normally kept beside yours as<name>.device-<time>, in the editor and in the device folder. The check goes by the time and size the device folder reports for the file: in a folder that reports no times, or keeps a file's old time when the file changes, as some USB and network folders do, a change that keeps the file's size goes unnoticed, and a folder over 64 MB that changes a file's time on its own can occasionally leave such a copy holding the file as you opened it, until VSCodroid has read each of its files once after an update from version 1.4.0 or earlier, which it does 64 MB per opening of the folder. A folder that reports no times cannot say which copy is newer when yours and the device folder's differ as you open it, as when another app changed a file you saved there in an earlier session: the editor keeps showing your version, and your next save of the file keeps the other app's beside it. If the device folder's version cannot be copied, as can happen in a network folder while it is offline even when no other app changed the file, or when the device folder reports that version as over 50 MB, your save stays inside VSCodroid and a notice says so. While the folder is open VSCodroid tries the save again by itself, at least every five minutes, and it goes through, without a second notice, once that version can be read or copied. If the folder reports file times, opening it again tries the save too; if that version cannot be read or copied then either, saves of the file wait inside VSCodroid until an open can. If it reports none, opening it again leaves both versions as they are, as above: VSCodroid goes on trying the save, and after VSCodroid restarts, your next save of the file sends it. In either kind of folder, an open that finds that version reported as over 50 MB keeps saves of the file inside VSCodroid until an open finds it smaller. - A file of a device folder that you delete in the editor is deleted in the device folder too, unless the device folder's version is one VSCodroid has not read: another app may have changed it since you opened the folder or last saved the file, by the same check as a save, or opening the folder could not read it. Such a file is kept in the device folder, and so is a folder holding it that you delete from the terminal; a notice says so, and the file comes back into the editor the next time you open the folder.
- An open that cannot list the folder holding a file leaves VSCodroid nothing to check that file against until an open can: a save held back before that open is no longer tried, and your next save or delete of the file replaces or removes the device folder's version without keeping a copy.
- The Explorer and the title bar show a device folder under its own name. A
folder opened in an earlier version is shown under a twelve-character code
such as
8e440ff38c8e, the name of its copy, and offers to reopen under its own name. While a file has unsaved changes or a terminal is open, Reopen asks you to save or close them first, since they would stay with the code; the files that were open come back with the folder. Don't Ask Again keeps the code for that folder. - A
.code-workspacefile opens as a multi-root workspace: open the file and choose Open Workspace. On a device folder its roots have to sit inside the folder you granted, because nothing outside that folder is reachable. - Create new files with Ctrl+N or by right-clicking in the Explorer.
- The default workspace is
~/projects/. Create subdirectories there for each project.
Tabs
- Open files appear as tabs at the top of the editor.
- Ctrl+W closes the current tab.
- Ctrl+Tab switches between open tabs.
- Drag tabs to reorder them.
Command Palette
The Command Palette is the fastest way to access any feature. Open it with Ctrl+Shift+P and start typing what you want to do.
Common commands:
Format Document-- auto-format the current fileChange Language Mode-- set syntax highlighting for a filePreferences: Open Settings (UI)-- open the settings editorPreferences: Open Keyboard Shortcuts-- view and customize shortcuts
Settings
Open the Command Palette (Ctrl+Shift+P) and run Preferences: Open Settings (UI).
VSCodroid stores settings in ~/.vscodroid/. Key defaults:
- Word wrap is on, in the editor and in the diff editor.
- Git path is preconfigured to the bundled Git binary.
- The terminal profile points to the bundled Bash.
To edit settings as JSON, use the Command Palette: Preferences: Open User Settings (JSON).
Text Size
VSCodroid: UI Scale, in the Command Palette, sets the size of the whole interface: the side bar, tabs, menus, status bar, panels and editor together. It offers 100%, 110%, 125% and 150%, but only the sizes that keep the page at least 320 CSS pixels wide, so most phones go up to 110% or 125% and tablets to 150%. The size is kept when the window reloads and when the app restarts. A size that does not take effect on your device is put back to 100%, and the command says so when you pick it.
To change the text in one place only, use the editor.fontSize and terminal.integrated.fontSize settings, which are remembered. Increase Editor Font Size in the Command Palette also works, but it is not bound to a key and it resets when the window reloads.
Android's Font size setting does not reach the editor's interface. Its Display size setting does, and it enlarges every app on the device.
Extra Key Row
When the soft keyboard is visible, a row of extra keys appears above it. Swipe it left or right to change page; the dots underneath show how many pages there are and which one you are on.
One exception, and it is deliberate: the row takes its height out of the page rather than covering it, so where the keyboard leaves almost nothing behind, the row stands down instead of taking the last of it. That is landscape on a phone, where the keyboard alone can be two thirds of the screen. Turn back to portrait, or put the keyboard away, and the row returns.
To hide the row altogether, for example while typing on a hardware keyboard, tap the remote indicator at the left end of the status bar and choose VSCodroid: Toggle Extra Key Row, or run it from the Command Palette. The row stays hidden, across restarts, until you run the command again.
How many pages there are depends on how wide your phone is. The row divides its width evenly among the keys on a page, so on a narrower screen it carries fewer keys per page and spreads them over more: five pages on a 411dp phone and wider, six at 360dp, seven at 320dp. The keys and their order never change, only where the page breaks fall. The tables below are the five-page layout; on a narrower phone read them as one list that is cut in more places.
Page 1, essential coding keys:
| Key | Purpose |
|---|---|
| Tab | Indentation, accept autocomplete |
| Esc | Close menus, cancel operations |
| Ctrl | Modifier for shortcuts (Ctrl+S, Ctrl+Z, etc.) |
| Alt | Modifier for shortcuts (Alt+Up/Down to move lines) |
| Shift | Modifier for selections, for the row's own keys (Shift+Tab, Shift+F12), and for Ctrl or Alt chords typed on the soft keyboard (Ctrl+Shift+P) |
| trackpad | The wide pad. Drag to move the cursor; see below |
| {} | Opening curly brace |
| () | Opening parenthesis |
{} and () insert only the opening character. The editor closes the pair for
you and leaves the cursor between the two.
Page 2, common symbols: ; : " / | ` & _
Page 3, brackets and operators: [ ] < > = ! # @
Page 4, function keys: F1 through F8
Page 5, the rest of the function keys and navigation: F9 through F12,
Home, End, PgUp, PgDn
The last two pages are the only place a touch user can reach any of those keys: no other page carries a function key, and the trackpad sends arrows only. Any shortcut the editor or an extension binds to one is a tap away.
The trackpad
The wide pad on page 1 stands in for the four arrow keys. Drag it and the cursor
moves, in the editor and the terminal, and a diagonal drag moves on both axes at
once. Dragging left or right also moves the caret in text boxes such as rename,
the Command Palette and find, and inside extension panels, and so do Home and
End. PgUp and PgDn work inside extension panels too, and in the Command
Palette they page the list, as dragging up or down moves through it. In a
number box, such as a number setting in the Settings editor, dragging left or
right does nothing; tap where the caret should go, or use Home and End.
Inside an extension panel, a drag past either end of a text box can move focus
to the next control.
It has three gears, and which one you are in depends on how far your finger has travelled since the drag began, not on how fast you are moving it. A short drag steps character by character. Keep going in the same stroke and the same amount of finger travel starts buying more movement, twice over, so one long drag crosses lines and then whole screens. Lift your finger and the next drag starts in the first gear again.
Long press
Touch and hold a key that has alternates and a small popup offers them:
| Key | Alternates |
|---|---|
{} |
[ and < |
() |
), ] and > |
" |
' and ` |
/ |
\ |
` |
~ |
Long press is the only route to ), ' and \: no page carries them, and a
latched Shift does not reach them either. The closing parenthesis matters most,
because auto-closing brackets usually supply it and leave you with no way to type
one when they do not. ~ is in the popup too, but it is not stranded there: the
row carries ` as a key of its own, and a latched Shift over it types ~.
Every other key sends one press, the same press a tap sends, and nothing on this row repeats. Tab, Esc and the rest press when you lift your finger, however long you held it, provided the finger stayed where it landed; one that slid away at any point sends nothing. Ctrl, Alt and Shift switch as soon as the hold is long enough for a long press, before you lift your finger, so what you type while still holding a lit Ctrl meets it just as it would after a tap, and lifting the finger changes nothing. A swipe that starts on a key turns the page, sends nothing and leaves a modifier as it was, and two quick taps send two presses.
Modifiers
Ctrl, Alt, and Shift are sticky -- tap once to activate for the next keypress. Tap again to deactivate. They highlight when active.
Three things behave differently from "the next keypress". Shift stays held for a whole trackpad drag, so dragging with Shift on selects text rather than moving the cursor once. All three clear by themselves when the soft keyboard hides. And Shift on its own is not applied to what you type on the soft keyboard, so for a capital letter hold the soft keyboard's own Shift; latch Ctrl or Alt as well and the row's Shift is carried into that chord, which is how Ctrl+Shift+P is typed.
Enter, Backspace and Delete take a latched modifier as well, even though the soft keyboard reports all three as an edit rather than as a key. So Ctrl+Enter and Ctrl+Backspace arrive as chords: Ctrl+Enter opens a line below without splitting the one you are on, rather than typing a plain newline.
Under a screen reader, the dots below the row are one item that reads "Key page 1 of 5", with any latched modifier named after it ("Key page 1 of 5, ctrl+shift held"). It is spoken again each time you swipe to another page, which is the only announcement that the keys under your finger have changed.
The keys on each page are defined in
android/app/src/main/kotlin/com/vscodroid/keyboard/KeyPageConfig.kt, and the
trackpad's gears in TrackpadGesture.kt beside it.
Common Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Ctrl+P | Quick Open (search files by name) |
| Ctrl+Shift+P | Command Palette |
| Ctrl+S | Save file |
| Ctrl+Z | Undo |
| Ctrl+Shift+Z | Redo |
| Ctrl+/ | Toggle line comment |
| Ctrl+D | Select next occurrence |
| Ctrl+Shift+K | Delete entire line |
| Alt+Up / Alt+Down | Move line up/down |
| Ctrl+` | Toggle terminal |
| Ctrl+B | Toggle sidebar |
| Ctrl+Shift+E | Focus file explorer |
| Ctrl+Shift+F | Search across files |
| Ctrl+Shift+X | Open extensions panel |
Terminal
Open the terminal with Ctrl+` or from the menu bar. VSCodroid includes a full terminal with real PTY support, so full-screen and interactive programs work natively: tmux, bash line editing, and the Node and Python REPLs.
Bundled Tools
All tools are available immediately with no installation or setup:
node -v # Node.js 24.x
npm -v # npm 11.x
python3 --version # Python 3.14.x
python3 -m pip --version # pip, bundled inside Python's site-packages
git --version # Git 2.55.x
bash --version # Bash 5.3.x
tmux -V # tmux 3.7c
make --version # GNU Make 4.4.1
ssh -V # OpenSSH 10.5p1 client
rg --version # ripgrep (powers VS Code search)
Using the Extra Key Row in Terminal
The Extra Key Row is especially useful in the terminal:
- Ctrl+C -- interrupt a running process (tap Ctrl, then tap C on keyboard)
- Ctrl+D -- send EOF / exit the shell
- Ctrl+L -- clear the terminal screen
- Tab -- autocomplete file and directory names
- Esc -- cancel a prompt, or leave copy mode in tmux
- Arrow keys -- navigate command history (Up/Down) and cursor (Left/Right). On a touch device these come from the trackpad on page 1 of the key row, not from buttons; drag it up or down to walk back through history
Multiple Terminals
- Click the + icon in the terminal panel to open a new terminal.
- Click the dropdown to switch between terminals.
- Each terminal is an independent bash session with its own working directory.
Running Code
# Run a JavaScript file
node app.js
# Run a Python script
python3 script.py
# Start a Node.js project
mkdir my-app && cd my-app
npm init -y
npm install express
node index.js
Extensions
VSCodroid uses the Open VSX extension registry. This is a free, open alternative to the Microsoft Marketplace. Most popular extensions are available.
Searching and Installing
- Open the Extensions panel: Ctrl+Shift+X or click the Extensions icon in the sidebar.
- Type the extension name in the search box.
- Click Install on the extension you want.
Extensions are downloaded from Open VSX and persist across app restarts.
Installing from a VSIX File
Run Extensions: Install from VSIX... from the Command Palette
(Ctrl+Shift+P) to install an extension you already hold as a .vsix file.
The picker it opens is the editor's own, not Android's. It starts in your home
folder, lists only files ending in .vsix, and shows only what VSCodroid can
see. A path typed into it reaches Downloads, Documents or an SD card, but a
file the browser or another app saved there is hidden from it, for the same
reason a folder opened there with File > Open Folder shows none of those
files. So bring the file inside first:
- Download the
.vsixwith the phone's browser. - Run VSCodroid: Open Folder from Device and grant the folder it landed in; the file appears in the Explorer. Android does not grant the Download folder itself, which is where a browser usually saves, so first move the file into a folder of its own, such as a new one inside Download, with the phone's Files app. A device folder is copied into the app for as long as it is open, so pick a folder holding little else. Files over 50 MB are not carried in at all, so a very large VSIX has to arrive another way.
- Open a terminal (**Ctrl+
**), which starts in that folder, and copy it across:cp name.vsix ~/`. - Run Extensions: Install from VSIX..., pick the file, and choose Reload Now when the notification offers it.
Signature checking plays no part in this. extensions.verifySignature decides
downloads from Open VSX and nothing else; a VSIX is never checked for a
signature whatever that setting says. What you do give up is the platform choice
the marketplace makes for you: VSCodroid asks Open VSX for the Alpine ARM 64
build of an extension that publishes one per platform, and a file you pick
yourself gets no such help, so take the alpine-arm64 one where the extension
offers it (see Extensions That Bundle a Compiled
Program). Nothing checks that
either: a VSIX built for the wrong platform installs, shows as enabled, and does
nothing. One built for a newer editor is refused outright, with a message naming
the version.
Pre-installed Extensions
These extensions come bundled with VSCodroid:
- ESLint -- JavaScript/TypeScript linting
- Prettier -- code formatting
- Tailwind CSS IntelliSense -- Tailwind autocomplete
- Python -- Python language support
VSCodroid also ships five of its own, which do not appear in the marketplace: the Get Started walkthrough, the Android bridge (device folders, the device browser, SSH keys and storage), Serve on Network, the process monitor in the status bar, and the editor menu entries that add Select All beside Cut, Copy and Paste.
VSCodroid opens on the editor's own dark theme, and it is not the only one installed. Nineteen colour themes ship with it: the Dark and Light defaults with their Modern and high-contrast variants, plus Abyss, Kimbie Dark, Monokai, Monokai Dimmed, Quiet Light, Red, Solarized Dark, Solarized Light and Tomorrow Night Blue. Switch with Preferences: Color Theme in the Command Palette, no download needed. Three file-icon themes ship too, Seti among them. Anything beyond these comes from the marketplace.
Recommended Extensions to Install
| Extension | What It Does |
|---|---|
| Error Lens | Show errors inline in the editor |
| Auto Rename Tag | Rename paired HTML/XML tags |
| Path Intellisense | Autocomplete file paths |
| REST Client | Send HTTP requests from the editor |
Extension Webviews
Extensions that use webview panels (such as theme configurators, documentation viewers, and AI assistants) render correctly in VSCodroid.
Jupyter Notebooks
The Jupyter extension (ms-toolsai.jupyter) installs from the Extensions view like any other. It reaches a notebook kernel through a messaging add-on it carries only in builds for desktop systems, so VSCodroid supplies an Android build of that add-on.
Notebooks run in a Python virtual environment. Create one in the terminal with python3 -m venv .venv, open a .ipynb file, choose Select Kernel, then Python Environments..., and pick that environment. If it does not have ipykernel yet, the extension installs it when the first cell runs, which takes about half a minute and needs a network connection. ipykernel depends on psutil, which PyPI has no Android build of; pip takes it from the prebuilt packages described in Python Packages Written in C.
If the extension offers to install jupyter and notebook, decline: that is a Jupyter server, whose dependencies cannot be built here and whose commands Android will not run from the app's storage.
The Android build of that add-on is pointed at by ZEROMQ_PREBUILD, which every process VSCodroid starts inherits. A Node project of your own pinned to zeromq 5.x or 6.0.x picks it up too, which is what lets it load at all here. To run such a project against its own copy instead, clear the variable for that command: ZEROMQ_PREBUILD= node app.js.
What Is Not Available
Some extensions are exclusive to the Microsoft Marketplace and not published on Open VSX. Notable examples include Microsoft's C/C++ extension. For most cases, open-source alternatives exist on Open VSX. GitHub Copilot Chat is the exception that needs no marketplace: it ships bundled.
SSH and Git
Generating an SSH Key
Generate the key from the terminal, naming the output file explicitly:
ssh-keygen -t ed25519 -C "your@email.com" -f ~/.ssh/id_ed25519
Press Enter twice at the passphrase prompts to leave the passphrase empty.
Name the output path with -f rather than accepting the default. OpenSSH derives its
default key path from the system user database, which an Android app sandbox does not
provide, so the default can resolve somewhere unwritable and fail with
Saving key "..." failed: No such file or directory.
Copying Your Public Key
Print the public key in the terminal, then select the output and copy it:
cat ~/.ssh/id_ed25519.pub
Paste it into your GitHub, GitLab, or Bitbucket account under Settings > SSH Keys.
Configuring Git
Set your identity before making commits:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Cloning a Repository
# SSH (after adding your key to GitHub)
git clone git@github.com:username/repo.git
# HTTPS
git clone https://github.com/username/repo.git
Common Git Operations
git status # See changed files
git add . # Stage all changes
git commit -m "Fix bug" # Commit
git push origin main # Push to remote
git pull # Pull latest changes
git log --oneline -10 # Recent commit history
git branch feature-x # Create a branch
git checkout feature-x # Switch to branch
VS Code's built-in Source Control panel (Ctrl+Shift+G) also works for staging, committing, and viewing diffs.
SSH Configuration
VSCodroid creates a default SSH config at ~/.ssh/config on first launch with sensible defaults:
StrictHostKeyChecking accept-new-- auto-accept new host keys on first connection- ed25519 identity file configured
- Keepalive enabled
You can edit ~/.ssh/config to add custom hosts:
Host myserver
HostName 192.168.1.100
User deploy
IdentityFile ~/.ssh/id_ed25519
Web Development
Creating a New Project
# React with Vite
cd ~/projects
npm install -g create-vite
node "$(npm root -g)/create-vite/index.js" my-react-app --template react --no-interactive
cd my-react-app
npm install
npm pkg set scripts.dev="node node_modules/vite/bin/vite.js" scripts.build="node node_modules/vite/bin/vite.js build"
npm run dev
# Express API
mkdir my-api && cd my-api
npm init -y
npm install express
The React steps avoid npm create vite@latest and the template's own vite scripts,
which stop with bad interpreter: Permission denied; npm and npx says
why. The template's lint and preview scripts need the same change:
npm pkg set scripts.lint="node node_modules/oxlint/bin/oxlint" scripts.preview="node node_modules/vite/bin/vite.js preview"
Dev Server Preview
When running a local dev server (Vite, Next.js, Express, Flask, etc.), you can preview it inside the editor, in a tab beside your code:
- Start the dev server in the terminal, from a
devscript that runs it throughnodeas the React steps above set it up:bash npm run dev # Output: Local: http://localhost:5173/ - Open the Command Palette (Ctrl+Shift+P) and run
Simple Browser: Show - Enter the URL, for example
http://127.0.0.1:5173/
The page opens in an editor tab with back, forward and reload buttons, and an icon to hand the page to your device's browser if you would rather see it full screen. Edit, save, tap reload, all without leaving the app.
Any loopback port works, whatever port your dev server picked.
If your dev server is on https
A preview served over https with a self-signed or private certificate is refused, and the editor now names the host it blocked and says why. Before, the tab simply came up empty and there was nothing to tell that apart from a server that was not running.
Plain http:// is the answer for a local preview: cleartext is permitted here precisely
because that is what dev servers speak. Installing your own CA through Android Settings
does not help for a page, and this is the one place where it makes a difference which
part of the app is asking. Pages are rendered by the system WebView, which trusts the
device's system roots and nothing else. The terminal does read a CA you installed,
because the app builds a certificate bundle from both halves of the device trust store
and hands it to git, to Python and to everything else there that speaks TLS. So the same
certificate can clone or pip install fine in the terminal and still be refused in a
preview tab.
Opening in the device's browser instead
If you would rather use the device browser, the terminal route still works:
- Open the Command Palette and run
Terminal: Open Last URL Link - The page opens in your device's browser
The terminal underlines the URL, but tapping it does nothing: VS Code only follows a
terminal link on Ctrl+click, and a touch tap carries no Ctrl. The command above exists
for exactly this case. Terminal: Open Detected Link... lets you pick from every link
currently on screen instead of just the last one.
npm and npx
npm installs packages as usual, including the Android builds that packages such as Rollup, Rolldown, Lightning CSS and oxlint publish for their native part:
npm init -y # Create package.json
npm install express # Install a package
npm run start # Run a script from package.json
Starting a package's program by name does not work: npx <tool>, npm create and
npm init <initializer>, and a package.json script such as "dev": "vite", all exit
with status 126 and Permission denied; when the program is a JavaScript file the
message reads /usr/bin/env: bad interpreter: Permission denied. npm starts those
through the file in node_modules/.bin, and Android refuses to execute a file inside
the app's storage. Run the program's JavaScript file with node instead, such as
node node_modules/vite/bin/vite.js for vite; the package's package.json names that
file under bin. A script that starts with node, like "start": "node server.js",
works as it is.
npm uses --prefer-offline by default to speed up installs by using cached packages when available.
Python Web Development
mkdir flask-app && cd flask-app
python3 -m venv venv
source venv/bin/activate
python3 -m pip install flask
python3 app.py
Package Compatibility
Some npm packages require C/C++ compilation and will not install because there is no compiler on the device. Use these alternatives:
| Package | Alternative | Notes |
|---|---|---|
better-sqlite3 |
sql.js |
SQLite compiled to WASM |
bcrypt |
bcryptjs |
Pure JavaScript |
sharp |
jimp |
Pure JS image processing |
node-sass |
sass |
Dart Sass, pure JS |
canvas |
@napi-rs/canvas or pureimage |
Check Open VSX availability |
See the Known Limitations section for more details.
Running and Debugging
VSCodroid ships one debug adapter: js-debug, the same one desktop VS Code uses for JavaScript and TypeScript.
The Configurations That Are Already There
Three launch configurations are written when the app first sets itself up. They belong to VSCodroid rather than to a project, so they are offered for every folder you open:
| Configuration | What it is for |
|---|---|
| Node.js: Run Current File | Runs the file in the active editor under the debugger |
| Attach to Node.js | Attaches to a Node process you started yourself with --inspect, on port 9229 |
| NestJS: Debug | Runs src/main.ts through ts-node, for a project that already has ts-node and tsconfig-paths installed |
The shortest route on a touch screen is Debug: Select and Start Debugging from the Command Palette (Ctrl+Shift+P): it lists all three and starts the one you pick. The Run and Debug icon in the activity bar shows the same three in a dropdown with a start button beside it.
Set a breakpoint by tapping the gutter to the left of a line number.
To give a project configurations of its own, open Debug: Select and Start
Debugging and choose Add Configuration... at the bottom of the list. That
creates .vscode/launch.json in the folder, and what you put there appears in
the same list beside VSCodroid's three.
Attaching to a Server You Started
Attach to Node.js is the one to reach for with a dev server, because it leaves
the server alone:
node --inspect server.js
Node prints Debugger listening on ws://127.0.0.1:9229/...; start Attach to
Node.js and it connects, and the process itself reports Debugger attached.
The configuration sets restart, so it reconnects when a watcher restarts the
process.
What Has No Debugger Here At All
- Python. The bundled Python extension carries no debugger of its own; it
points at Microsoft's separate
ms-python.debugpy, which VSCodroid does not bundle. - Browsers. js-debug drives Chrome or Edge through a companion that has to run on the machine you are sitting at, and that companion cannot run here. Debug the server side, and view the page in the preview tab or the device browser.
- Everything else. Ruby and Java are toolchains, not debuggers, and neither ships an adapter. A debug extension written in JavaScript and published on Open VSX may work; one that ships a program compiled for desktop Linux will not (see Extensions That Bundle a Compiled Program).
On-demand Toolchains
Beyond the bundled tools (Node.js, Python, Git, Bash), VSCodroid offers additional languages as on-demand downloads.
Available Toolchains
| Language | Download Size | Installed Size | Includes |
|---|---|---|---|
| Ruby 4.0 | 10.5 MB | 39 MB | ruby, gem, irb, bundler, rake |
| Java 17 (OpenJDK) | 56.5 MB | 156 MB | java, javac, jar, jshell |
Installing During First Run
The Language Picker appears on first launch. Select the languages you want and they download in the background.
Toolchains are never bundled inside the APK. Play Store installs fetch them as on-demand asset packs; sideloaded installs download them over HTTPS from the latest GitHub Release. Either way they land in the app's own storage and survive app updates.
Installing After Setup
The Language Picker stops appearing once you answer it with Continue or Skip, but the screen it offers stays reachable, by two routes. From the editor, run VSCodroid: Manage Toolchains from the Command Palette (Ctrl+Shift+P). From outside it, touch and hold the VSCodroid icon (on the home screen or in the app drawer) and choose Manage toolchains. Both open the same screen, and installing and removing work exactly as they do during setup, so a language you skipped is not lost.
The launcher shortcut is there because reaching this screen matters most when the editor is the part that will not start, so at least one way in does not depend on it.
Using Installed Toolchains
New terminals automatically pick up toolchain PATH changes. No app restart is needed.
# Ruby
ruby -v
gem install sinatra
ruby app.rb
# Java
javac -version
javac Main.java
java Main
A command a gem installs (rubocop, rails) starts working once you switch away from
VSCodroid and back, in a new terminal, the same delay as a command pip installs; see
Python Command-Line Tools.
Removing Toolchains
Open the Toolchains screen by either route in Installing After Setup and remove it there.
Tips and Tricks
tmux for Persistent Sessions
tmux is bundled and works with real PTY support. Use it for long-running tasks that you want to survive terminal tab closes:
tmux new-session -s build # Start a named session
# Run your long build...
# Ctrl+B then D to detach (session keeps running)
tmux attach -t build # Reattach later
tmux list-sessions # See all sessions
tmux kill-session -t build # End a session
Note: tmux is a standalone tool, not integrated with VS Code's terminal tabs.
Process Monitor
The status bar shows a phantom process count. This tells you how many background processes VSCodroid is using.
- Click the process count to see a detailed process tree in the Output panel.
- Before you open anything, the count is the app's own background processes. Each terminal tab and each running language server adds 1.
- At 6 the monitor warns you and at 14 it reports an error; both offer Show Details, which marks the language servers that have sat idle for five minutes or more.
Quick File Navigation
- Ctrl+P then start typing a filename -- the fastest way to open files in large projects.
- Ctrl+G to go to a specific line number.
- Ctrl+Shift+O to jump to a symbol (function, class) in the current file.
Multi-cursor Editing
- Ctrl+D -- select the next occurrence of the current selection.
- Ctrl+Shift+L -- select all occurrences.
- Hold Alt and tap to place additional cursors (on external keyboard).
Zen Mode
Ctrl+K Z enters Zen Mode -- a distraction-free fullscreen editing experience. Press Esc Esc (double Esc) to exit.
Saving Battery
- Close terminals you are not using. Each open terminal is a separate bash process.
- An idle language server is not killed, by a timer or by hand: its extension restarts it within a second. Disabling the extension that starts it is what frees the slot; VSCodroid: Show Process Tree marks the idle ones.
- Avoid leaving dev servers running in the background when not in use.
Touch Gestures
The editor and the file tree answer the gestures a phone expects, but nothing on screen says so. These are the ones that work.
In a file:
- Tap to place the caret. Double-tap to select the word under your finger.
- The soft keyboard comes up for a tap on the text, a line number or the space under the last line, and stays down while you swipe to scroll. Put it away with Back or the hide key in the navigation bar and it stays down until you tap the text again.
- To read a file without the keyboard coming up at all, run File: Toggle
Active Editor Read-only in Session from the Command Palette, or list the
files in the
files.readonlyIncludesetting. A tap then only moves the caret, and pressing and holding still offers Copy. Run the command again to edit. - Press and hold for about a second, then lift, to open the menu: Cut, Copy, Paste, Format Document, Rename Symbol, Go to Definition and the rest. Every item runs on a tap.
- There are no drag handles over code, because the editor draws its own selection rather than the system's. To extend one, tap shift on the key row and drag the trackpad.
In the file tree:
- Press and hold a file for about a second, then lift: Cut, Copy, Rename, Delete and more.
- Paste appears when you hold the destination: a folder, or the empty space under the last file for the project root. Holding another file shows no Paste, which is how VS Code behaves on a desktop as well.
- So moving a file is: hold it, tap Cut, hold the folder you want it in, tap Paste.
Keyboard Tips for Touch
- Connect a Bluetooth keyboard for the best experience with complex editing.
- Without an external keyboard, rely heavily on the Command Palette (Ctrl+Shift+P) and the Extra Key Row.
- Pinch-to-zoom is disabled to prevent layout issues; Text Size lists what makes things larger.
Known Limitations
Native npm Packages
Packages that require C/C++ compilation (node-gyp) fail on VSCodroid because there is no C compiler on the device. This affects packages like better-sqlite3, bcrypt, sharp, canvas, and node-sass. Pure JavaScript or WASM alternatives exist for most of them (see the Web Development section).
Python Packages Written in C
pip is bundled and installs anything written in pure Python. A package with a
compiled part is different, for two reasons, in the order pip hits them.
There is often no wheel to download. This interpreter reports its platform as
android-24-arm64_v8a, which is what it is, and PyPI carries no Android wheels
for most compiled packages. Pip then falls back to building from source, and
there is no C compiler on the device, so that fails too. The error you see names
the missing build tool rather than either of these, which is why it reads as
something you could install your way out of.
VSCodroid points pip at prebuilt Android builds of a few of them, so these install like any other package:
numpy2.5.0pandas3.0.5pydantic-core2.41.5, which is whatpydantic2.12 needs. The newestpydanticwants a later one, so install it aspip install "pydantic<2.13".psutil7.2.2, whichipykernelneeds for Jupyter notebooks
Each is available at that version only. lxml, pygame, matplotlib, Pillow
and scipy still cannot be installed.
The setting lives in ~/.pip/pip.conf, which VSCodroid rewrites on every launch.
Put your own pip settings in ~/.config/pip/pip.conf instead: pip reads it
afterwards, and any key there overrides the one VSCodroid wrote. Two effects of
VSCodroid's setting are worth knowing:
- pip prefers the newest release of any package that has a ready-made build over
a newer one it would have to build from source, for every package and not only
the ones above.
pip install name==<version>asks for a specific release. - pip reads the page listing those builds on every install, once for each package
it looks up. With no network at all that adds a few seconds per package before
pip carries on. On a network that blocks github.io without refusing the
connection, pip waits out its timeouts instead, about a minute and a half per
package, so an install that pulls in many packages can take far longer than
usual. To switch it off, for example on such a network or when installing from
local files, put
find-links =with nothing after it under[global]in~/.config/pip/pip.conf.
turtle and tkinter are not included at all. Tk draws into a desktop window,
and this app has no window to give it.
For graphics, the practical route is to write a file and look at it. An image
preview updates on its own when the file changes, so a program that rewrites a
PNG or an SVG in the workspace acts as a display you can watch while you edit.
Python's own zlib is enough to write a PNG with no packages at all. For
anything interactive, serve it: python3 -m http.server and open the address, as
in Dev Server Preview above.
Python Command-Line Tools
Some packages install a command as well as a module: pytest, black, httpie,
cowsay. These work, with one delay worth knowing about: a command you have just
installed starts working once you switch away from VSCodroid and back, not straight
away.
$ pip install cowsay
$ cowsay -t hi
bash: /data/.../usr/bin/cowsay: /data/.../usr/bin/python3: bad interpreter: Permission denied
Switch to another app or the home screen, come back, open a new terminal, and the
same line works. A terminal that already tried the command remembers where it
failed; hash -r there makes it look again.
The delay comes from how the command is made to run at all. Android does not let
an app run a program out of its own storage, and what pip writes is exactly that:
a short text file starting with #! and the path to the interpreter. VSCodroid
keeps a small table of what each command means and starts the interpreter itself,
which is allowed. That table is rebuilt when the app starts and when it comes back to the
front, so a command installed while you are in the editor is not in it yet, and until then you get the message
above. It names python3, so it reads as a broken Python; Python is fine, and the
interpreter it names runs perfectly when you call it yourself. It is the one-line
launcher that cannot start.
If you would rather not wait, run the module. It does the same thing and works the moment pip finishes:
python3 -m pytest
python3 -m black .
python3 -m cowsay -t hi
A command installed inside a virtual environment is the exception: it does not
start at all, and switching away and back does not change that. pip writes it into
the environment's own bin directory, and VSCodroid fills its table only from
usr/bin, where pip puts a command outside a virtual environment. With the
environment active, run the module instead, for example python -m pytest.
pip itself is the same shape and is already handled: pip and pip3 are set up
as shell functions that call python3 -m pip, so they work in the terminal
without anything on your part. A build task that runs outside a shell does not see
those functions, so write python3 -m pip in tasks.json and in any script.
The Python Formatter Is Not in Search Results
Open a Python file and VSCodroid offers to install Black Formatter by
ms-python. Accept it and Format Document works straight away: the extension
carries its own copy of black, so nothing needs installing with pip.
The offer exists because the extension cannot be found any other way. Open VSX does not return it for a text search, its own API included, so the Extensions view cannot surface it however you phrase the query. If you dismissed the offer, ask for it by identifier instead:
@id:ms-python.black-formatter
That returns exactly one result. @id: works for any extension a search does not
surface; the identifier is the publisher.name pair on its registry page.
What a search does return is Black by mikoz. That one also formats Python,
but only after you install black yourself:
pip install black
Until you do, Format Document does nothing at all. There is no error and no
prompt; the status bar shows "Running black" and stays that way.
The shortcut for Format Document here is Ctrl+Shift+I, not the Shift+Alt+F
used on the desktop.
Time Zones In Python
A named time zone raises instead of resolving:
>>> from zoneinfo import ZoneInfo
>>> ZoneInfo("Asia/Jakarta")
zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key Asia/Jakarta'
zoneinfo reads the operating system's time zone database, from
/usr/share/zoneinfo and three sibling paths. Android keeps its own database
somewhere else entirely and ships none of those, so the lookup finds nothing.
Install the database as a package and it works from then on, including for
pandas, croniter and anything else that asks zoneinfo for a zone:
pip install tzdata
datetime.now(), time.time() and UTC never needed this. It is named zones only.
Packages With Prebuilt Binaries
Some packages compile nothing. They download a ready-made binary chosen by
platform name, from a fixed list their own installer carries, and Android is not
on those lists. The install then stops with a message naming the platform it did
not recognise, such as Unsupported platform: android arm64 LE. workerd, which
Cloudflare Workers projects pull in through Wrangler, is one of these.
Nothing on the device changes that. The Android build is not published, and taking the Linux one instead would fail later rather than sooner: it is built against a different C library, and an app may not execute a file from its own data directory.
npm install --ignore-scripts installs the rest of the tree, so everything that
does not need that particular binary works. What needs it does not run.
This is not every package with a native part. Rollup, Rolldown, Lightning CSS and oxlint publish Android builds that Node loads as libraries, and npm installs them, which is why VSCodroid reports the platform it actually is rather than pretending to be Linux. esbuild publishes one too, but as a program: its install step runs it, Android refuses to execute it from the app's storage, and the install fails. Vite 8 does not need esbuild; Vite 7 and older depend on it and do not install.
Toolchains Must Be Started by Name
Android refuses to execute any file inside an app's data directory, which is where
installed toolchains live. VSCodroid works around it by handing the file to the
system loader instead, and it does that two ways: a bash function per command, and
a small program on PATH that every other kind of start finds.
So a toolchain command works when it is started by its bare name, whoever starts
it: typing ruby in a terminal, bash -c, sh -c, a make recipe, an npm
lifecycle script, a VS Code task of either kind, and a process an extension or a
language server starts directly.
What still fails is a start that names a path instead of a command:
- an absolute path such as
$JAVA_HOME/bin/java, which is not aPATHlookup at all - a toolchain that forks its own helper by absolute path, which is what the JDK's
lib/jspawnhelperdoes jshellstarted anywhere but bash, because its default engine starts a second JVM that way; the terminal'sjshellruns your snippets in its own JVM instead- a script under the app's storage run by its own path: Android refuses the script file itself, before its
#!line is ever read. Run it asruby script.rbinstead
npm and npx are reached the same two ways: a bash function in a shell, and a
program on PATH for everything else. So sh -c 'npm -v', timeout 60 npm install
and a tool that runs npm install itself all find them, as the terminal does.
Android Phantom Process Limit
Android 12 and later enforce a system-wide limit of 32 phantom processes (background processes spawned by apps). VSCodroid minimizes its footprint:
| Component | Phantom Processes |
|---|---|
| Bootstrap | 1 |
| Node.js server | 1 |
| File watcher | 1 |
| Extension Host | 0 (runs as worker thread) |
| ptyHost | 0 (runs as worker thread) |
| Each terminal tab | 1 (bash) |
| Each language server | 1 |
What the status bar shows on a cold start, before you do anything, is the app's own share. Nothing sheds a language server automatically: a killed one is restarted by its extension within a second. If you hit the limit (other apps compete for the same 32 slots), close unused terminals and disable the extensions whose language servers VSCodroid: Show Process Tree marks idle.
Memory Usage
VSCodroid typically uses 400-700 MB of RAM. On devices with 4 GB or less, you may experience occasional restarts under memory pressure. Tips:
- Close browser tabs and other apps to free RAM.
- Limit concurrent terminals to 1-2.
- Language servers are the biggest memory consumers. Nothing sheds them automatically, because their extensions restart them; disable the extensions you are not using. VSCodroid: Show Process Tree marks the idle ones.
os.cpus() Returns Empty
os.cpus() returns an empty array on Android. This is cosmetic -- tools that display CPU core counts may show 0, but actual performance is unaffected.
Microsoft-only Extensions
Extensions exclusive to the Microsoft Marketplace (such as Microsoft C/C++ and some other Microsoft-published extensions) are not available on Open VSX. Check Open VSX for community-maintained alternatives. GitHub Copilot Chat is not affected: it ships built in and works on device.
Claude Code Reports "terminated by signal SIGSYS"
An Android app may only make the system calls the platform's C library exposes,
and a call outside that list is not an error a program can recover from: the
kernel stops it there. The Claude Code extension carries its own program, whose
runtime asks for epoll_pwait2, and that call is on the list only from Android
15 onward.
VSCodroid answers that one call itself, so sign-in and everyday use work on
Android 13 and 14 as well. If the panel still reports Claude Code process
terminated by signal SIGSYS, or claude in a terminal prints Bad system
call, a newer release of the extension is asking for a call VSCodroid does not
answer yet. Please report it with your Android version and the extension
version; there is nothing to change on your side.
Extensions That Bundle a Compiled Program
Extensions written in JavaScript, TypeScript or WebAssembly work. An extension that carries a program compiled for desktop Linux may not, and when it does not, the way it fails is the real problem: it installs, it shows as enabled in the Extensions panel, and then its features are simply absent. No error, no notification, nothing on screen. That silence is the editor's own behaviour, not a fault in VSCodroid: a release build writes an extension's startup failure to a log and deliberately raises no notification for it.
Two walls stand behind this, and they are not the same wall. The first is that Android's C library is not the one desktop Linux distributions build against, so a whole program compiled for them cannot start here at all. An add-on loaded into the editor is the softer case: VSCodroid ships a compatibility layer that lets add-ons built for desktop Linux load anyway, and the ones inside the app depend on it. That layer is generated from the add-ons the app itself carries, supplying the library names and the exact functions those ask for, so an add-on you install later loads only if what it asks for happens to fall inside that same set. An add-on built against GNU's C++ standard library is outside it altogether, and even a load that succeeds is not a promise: the two C libraries lay some structures out differently, so an add-on can start and then misbehave.
The second wall is that Android refuses to execute any file inside an app's own storage, which is exactly where an installed extension lives, so even a correctly built program has to be handed to a loader by something else. VSCodroid asks the marketplace for the musl build wherever an extension publishes one, which is what makes that route possible at all, but the extension itself then has to offer a setting that lets its command be prefixed. Almost none do.
How to recognise it. The extension is installed and enabled, its commands are missing from the Command Palette or do nothing when run, and the Problems panel and status bar stay empty. Run Developer: Show Logs... from the Command Palette and read the extension host log; the reason is there and nowhere else.
One variant is loud rather than silent. An extension that publishes a
separate build per platform, with no musl build and no platform-independent one,
refuses to install at all, with a dialog reading The 'publisher.name' extension
is not available in VSCodroid for the Alpine ARM 64 platform. Alpine is not what
your phone is running; it is the build VSCodroid asks for, for the reason above.
Read that message as "this extension publishes nothing that can run here".
What to install instead. Prefer language support written in JavaScript or TypeScript, or compiled to WebAssembly. On an extension's Open VSX page, a download list naming several operating systems and processors is certain to be shipping a compiled program. A single download covering all platforms is not proof of the opposite: some extensions carry a compiled helper inside that one package, and the helper is the part that can fail.
The Interface Follows Your Phone's Language
Menus, commands, settings descriptions and dialogs come up in the language the phone is set to. There is nothing to turn on and nothing to install: change the language in Android's Settings, then start VSCodroid.
Thirteen languages ship inside the app: Chinese (Simplified and Traditional), Czech, French, German, Italian, Japanese, Korean, Polish, Portuguese (Brazil), Russian, Spanish and Turkish. A phone set to Portuguese gets the Brazilian translation wherever it is, because that is the only Portuguese the editor has been translated into. Any other language leaves the interface in English.
The translations are the ones the desktop editor uses, built into the app from
Microsoft's vscode-loc packs. A display-language pack from Open VSX is neither
needed nor used, and installing one adds no language to the list above.
VSCodroid's own screens follow the same list: the setup progress, the toolchain picker, and the notifications and dialogs the app puts on screen are translated into those thirteen languages too. On Android 13 and later they can be set separately from the phone, under Settings, Apps, VSCodroid, Language, and the editor follows that choice as well.
VSCodroid's own commands, settings and the Get Started walkthrough are translated into the same thirteen languages. An extension you install from Open VSX carries its own translations if its author wrote any, and English if not.
Two things stay English whatever the phone is set to. The occasional editor string the translation packs do not cover, roughly one in fifty. And the messages an extension shows while it is running, VSCodroid's own included: what is translated for an extension is what its manifest declares, its commands and its settings, while the notices it puts on screen as it works are written into its code.
Changing the language while VSCodroid is running takes effect on the spot: the editor reloads in the new one. What does not change is anything already written, including the terminal's output and the app's own notifications from before the change.
No Multi-window
VS Code's web client runs as a single window. You cannot open multiple VS Code windows side by side. However, you can use Android's split-screen mode to pair VSCodroid with another app (like a browser for previewing).
Storage
Core installation extracts approximately 603 MB to internal storage. With both toolchains installed, expect around 800 MB. Setup needs about 738 MB free before it starts, which is more than it ends up occupying because extraction needs room to work. If it refuses, it asks for the shortfall it measured rather than the whole figure, so a device part of the way through is asked only for what is missing. Beyond it, keep a few hundred MB free for node_modules, build artifacts and caches.
Troubleshooting
Blank Screen on Launch
If the app shows a blank screen after opening:
- Wait 10-15 seconds -- the Node.js server may still be starting.
- If it persists, force-close the app and reopen it.
- If the issue continues, clearing app data forces a fresh extraction. Read the warning below before you do it.
Clearing app data deletes every project in
~/projects/.On a new install
~/projects/is inside the app's internal storage, which Clear Data wipes along with everything else, and nothing is backed up. An install from before 1.2.0 that already had a projects directory in the app's area of shared storage (Android/data/com.vscodroid/files/projects) keeps using it, and Clear Data wipes that too. New installs stopped using that location because shared storage cannot hold a symbolic link, sonpm installfailed there on the first package that ships an executable.
Rescue anything unsaved first. Which route is open to you depends on whether the editor still works, and on a blank screen it does not:
If the editor will not open, nothing outside the app reaches a new install's
projects: internal storage is not exposed over USB or MTP, and adb pull cannot
read it from a release build. What is left:
- A debug build is readable with
adb shell run-as com.vscodroid.debug, and its projects can be copied out from there. The release builds refuserun-as. - An install that still keeps its projects on shared storage can be read as before, with USB debugging on:
adb pull /storage/emulated/0/Android/data/com.vscodroid/files/projects
Some devices also expose that path over MTP when plugged in.
Everything else needs the editor, which is why the routes below are worth taking before a screen goes white rather than after.
If the editor does open and you are clearing data for some other reason, two in-app routes exist:
- Push to a remote, if the project is a git repository. This is the only route that preserves history.
- Or run VSCodroid: Open Folder from Device from the Command Palette
(Ctrl+Shift+P), choose a folder outside the app such as Documents, and copy
your work there. A folder opened that way lives outside the app's storage, so
Clear Data does not touch it. It does not carry
.gitor.env, along withnode_modules,.gradle,.idea,venvand__pycache__: the device-folder sync skips those directories, so this rescues your files but not your repository history and not your local configuration.
Then clear app data from Settings > Apps > VSCodroid > Clear Data and relaunch.
Terminal Commands Not Found
If node, python3, git, or other tools show "command not found":
- Open a new terminal tab. PATH is set up when a new bash session starts.
- Verify the tool exists:
ls -la $(which node)(should point to the bundled binary). - If the issue persists, close the app completely and reopen.
Extensions Not Installing
- Check your internet connection -- extension search and download require connectivity.
- Search directly on open-vsx.org to verify the extension exists there.
- Some extensions require a newer editor than the one you have. Run About from the Command Palette (
Ctrl+Shift+P) to see which version VSCodroid is built on, compare it with the extension's requirement on open-vsx.org, and try an older version of the extension if it asks for more. An extension that needs a newer editor does not report an error -- it installs, never activates, and logs nothing, so this is worth checking whenever a freshly installed extension appears to do nothing.
npm Install Fails
If npm install fails with errors:
- EACCES / permission errors can mean an install step tried to run a program the package downloaded, which Android does not allow inside the app's storage; esbuild is one such package (see Known Limitations). If it is about writing a file or folder (
mkdir,open) rather than running a program, make sure you are working inside~/projects/or your home directory, not in a system path. - node-gyp / compilation errors -- the package requires native compilation. Use a pure JS alternative (see Known Limitations).
- Unsupported platform errors come from a package whose prebuilt binaries have no Android build, so there is nothing to install (see Known Limitations).
- Network timeout -- check your internet connection. npm uses
--prefer-offlineby default, so cached packages install without network.
Python: Installed, and Then Something Fails
bad interpreter: Permission deniedafter installing a package that brings a command with it (pytest,black,httpie). Switch away from VSCodroid and back, then use a new terminal, and the command works; to use it without waiting, run it as a module:python3 -m pytest. A command installed inside a virtual environment never starts, however often you come back to the app; run it as a module there too, for examplepython -m pytest. See Python Command-Line Tools for why the message namespython3when Python is not the problem.Format Documentdoes nothing in a.pyfile and the status bar sticks on "Running black". That is the formatter a marketplace search finds, which needs black installed separately (pip install black) and says nothing when it is missing. Opening a Python file offers you one that needs no pip step; see The Python Formatter Is Not in Search Results.ZoneInfoNotFoundErrorfromzoneinfo,pandasor anything that resolves a named time zone.pip install tzdataand it works from then on; see Time Zones In Python.ModuleNotFoundError: No module named 'tkinter'(or'turtle'), including from a package built on them such ascustomtkinter. Neither is included, and pip cannot add them:pip install tkinterfinds no such package, andpip install tkinstalls an unrelated one. To show graphics, write a PNG or an SVG and keep it open in a preview, or serve a page and open it in the browser; see Python Packages Written in C.
Git Push/Pull Fails
- Permission denied (publickey) -- generate an SSH key with
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519in the terminal and add it to your GitHub/GitLab account. The-fis required; see Generating an SSH Key for why. - SSL certificate error -- the CA bundle the terminal uses is built from your device's own trust store: the system roots, plus any certificate authority you installed yourself through Android Settings, under the CA-certificate flow in the device's security settings. git and Python are both given it, so a private or corporate CA works for
git cloneand forpip installalike, from the next time you open the app -- the bundle is rebuilt at launch, not while the app is running. If you would rather not install a CA on the device, an SSH remote (git@) instead ofhttps://is still the shortest route to an internal host. Two things that bundle does not reach: npm, which has its own trust store, and pages loaded inside the editor, which use the system roots only.
App Uses Too Much Storage
To reclaim space:
# Clear npm cache
npm cache clean --force
# Remove node_modules from old projects
rm -rf ~/projects/old-project/node_modules
# Clear pip cache
python3 -m pip cache purge
# Check disk usage
du -sh ~/projects/*
du -sh ~/.vscodroid/extensions/*
To remove an installed toolchain, run VSCodroid: Manage Toolchains from the Command Palette, or touch and hold the app icon and choose Manage toolchains; see Installing After Setup.
App Crashes or Restarts Unexpectedly
This is usually caused by Android's memory management killing background processes:
- Close other apps to free RAM.
- Reduce the number of open terminal tabs.
- Check the process monitor in the status bar -- if phantom count is high, close unused terminals.
- On devices with 4 GB RAM or less, consider keeping only one project open at a time.
- If it keeps happening, send a report; see Sending a Bug Report.
Dev Server Not Accessible in Browser
If the preview tab or the device browser opens but the page does not load:
- Verify the server is running in the terminal (check for errors).
- Use the host and port the dev server printed.
http://localhost:PORTandhttp://127.0.0.1:PORTreach the same loopback server, and either works.0.0.0.0is an address to bind to, not one to browse to. - To reach the server from another device on the same network, restart it
bound to every interface (
--host 0.0.0.0for Vite,-H 0.0.0.0for Next.js,--bind 0.0.0.0for Python) and run VSCodroid: Serve on Network from the Command Palette for the address the other device should use.
WebView Crash Recovery
If the editor UI crashes but the app stays open, VSCodroid automatically recovers the WebView and reconnects to the running server. Your terminal sessions and unsaved work in the editor state are preserved.
Recovery is bounded, because reloading a page that is itself the cause only repeats the crash. Three crashes inside a minute are recovered from as normal; a fourth stops the automatic reload and puts up a page saying so, with a Try again button that reloads the editor when you are ready. The server keeps running behind it either way, so nothing needs force-closing.
Sending a Bug Report
If the editor freezes, reloads by itself or the app closes, run VSCodroid: Copy Bug Report from the Command Palette once the editor is back. The report opens in a new editor tab: the device and app version, how Android recorded the app's recent exits (one it declared not responding shows as ANR, one closed to free memory as LOW_MEMORY), each time the process that draws the editor died, the newest crash logs and the last 200 lines of the server log. Nothing is sent anywhere.
Read it before you share it. The server log can name your files and folders, and you can delete any line you want kept private. Then tap Copy in the notification that comes with it, or Copy Bug Report in the status bar, which stays there while the report is open, and paste the report into an issue at github.com/rmyndharis/VSCodroid/issues.
VSCodroid is built from the MIT-licensed Code - OSS source code. Not affiliated with or endorsed by Microsoft Corporation. "Visual Studio Code" and "VS Code" are trademarks of Microsoft. Uses Open VSX extension registry, not Microsoft Marketplace.
VSCodroid