VS Code (LaTeX Workshop)

Add the LaTeX Workshop extension to Visual Studio Code and a general-purpose code editor becomes a serious LaTeX environment: it compiles on every save, shows the PDF in a side-by-side tab, and lets you jump between source and PDF in both directions. This page walks through setup, how builds work (recipes and tools), and SyncTeX integration.

What LaTeX Workshop is

VS Code does not typeset TeX itself. The actual compiling is done by a distribution you install on your machine — TeX Live (or MiKTeX / MacTeX). LaTeX Workshop, by James Yu, is the bridge between the editor and that distribution: it launches builds, previews the PDF, and adds completion, syntax highlighting, jump-to-definition for \ref/\cite, an outline view, and more. Its Marketplace ID is James-Yu.latex-workshop.

The one prerequisite is that the TeX commands are reachable on your PATH. The extension simply spawns executables such as latexmk or pdflatex as child processes, so if latexmk --version works in a terminal, the extension will almost certainly work too. Conversely, choosing an engine or configuring Japanese fonts is a matter for the distribution, not for the extension.

Setup

The steps are simple. Install VS Code, install a distribution such as TeX Live (in 2026, TeX Live 2026) and make sure it is on your PATH. Then open the Extensions view (Ctrl/Cmd+Shift+X), search for “LaTeX Workshop,” and install it. Right after changing the PATH, restart VS Code — ideally the whole OS — so the new environment is picked up. Open a .tex file and the TeX activity-bar icon on the left gives you build and preview commands.

Settings live in **settings.json** (from the Ctrl/Cmd+, Settings UI, use “Open Settings (JSON)” in the top-right; you can edit either the global user file or a per-project .vscode/settings.json). The three keys worth knowing first are:

  • latex-workshop.latex.outDir** — where intermediate files and the PDF go. Default %DIR% (next to the .tex). Setting it to e.g. out keeps your source folder uncluttered.
  • latex-workshop.latex.autoBuild.run** — what triggers an automatic build: onFileChange (default; watches dependencies), onSave (on save), or never (manual only). If you want predictable behavior, onSave is a safe pick.
  • latex-workshop.view.pdf.viewer** — where the PDF appears: tab (default; a tab inside VS Code), browser, or external. For frictionless SyncTeX, tab is the best choice.

A minimal starting point is just this — collect output in out/, build on save, and show the PDF in the built-in tab:

settings.json
{
  "latex-workshop.latex.outDir": "%DIR%/out",
  "latex-workshop.latex.autoBuild.run": "onSave",
  "latex-workshop.view.pdf.viewer": "tab"
}

%DIR% is a placeholder that expands to the directory of the root file being processed; it reappears in recipes below. After a build the extension can also tidy up or keep intermediate files (.aux, .log, …) via latex-workshop.latex.autoClean.run, but settling the output directory and the trigger is enough to get a feel for it.

Build recipes and tools

Builds in LaTeX Workshop have two layers: “tools” and “recipes.” A tool (latex-workshop.latex.tools) defines a single command to run — name, command (the executable), and args. A recipe (latex-workshop.latex.recipes) is an ordered sequence of tools, with a name and a tools array listing tool names. A flow like “pdflatex → bibtex → pdflatex → pdflatex” — running the bibliography pass and then re-running — is expressed as one recipe.

With no configuration, the extension uses its built-in default recipes. The first is a lone **latexmk**, and that is the intended default (when latex-workshop.latex.recipe.default is "first", the top recipe in the list is chosen; set it to "lastUsed" to remember the recipe you last picked). Because latexmk inspects dependencies and re-runs exactly as many times as needed, you never have to count passes for cross-references, the table of contents, or the bibliography. The default latexmk tool is defined roughly like this:

settings.json
{
  "name": "latexmk",
  "command": "latexmk",
  "args": [
    "-synctex=1",
    "-interaction=nonstopmode",
    "-file-line-error",
    "-pdf",
    "-outdir=%OUTDIR%",
    "%DOC%"
  ],
  "env": {}
}

Reading the arguments: -synctex=1 emits the SyncTeX data discussed below; -interaction=nonstopmode runs straight through instead of halting for input on an error; -file-line-error prints errors as “file:line: message,” making it easy to jump to the offending spot. -pdf tells latexmk to produce PDF directly via pdfLaTeX. %OUTDIR% expands to your outDir, and %DOC% to the root file’s path without its extension (other placeholders include %DOCFILE% = filename without extension and %DIR% = the root’s directory).

The default recipes also include engine variants latexmk (lualatex) and latexmk (xelatex), plus **latexmk (latexmkrc)**, which runs latexmk %DOC% with no extra arguments and defers everything to a .latexmkrc. For Japanese, that “put it all in .latexmkrc” approach is the cleanest. Drop a .latexmkrc at the project root and name the engine and converter. Here is an upLaTeX + dvipdfmx setup — the classic combination for Japanese papers in the sciences:

.latexmkrc
$latex = 'uplatex -synctex=1 -interaction=nonstopmode -file-line-error %O %S';
$bibtex = 'upbibtex %O %B';
$biber = 'biber --bblencoding=utf8 -u -U --output_safechars %O %S';
$makeindex = 'upmendex %O -o %D %S';
$dvipdf = 'dvipdfmx %O -o %D %S';
$pdf_mode = 3;
$max_repeat = 5;

In essence you assign uplatex to $latex, dvipdfmx to $dvipdf, and set $pdf_mode = 3 to choose the “build a DVI, then convert to PDF with dvipdfmx” path ($pdf_mode = 1 is pdfLaTeX directly, 4 is LuaLaTeX). The index goes through upmendex and the bibliography through upbibtex, which handles Japanese well. %S, %O, and %D are latexmk’s placeholders for the source, options, and output file. Now, on the VS Code side, you simply pick the latexmk (latexmkrc) recipe and never encode the engine choice in settings.json.

If you would rather keep everything in settings.json without a .latexmkrc, define your own tool and recipe and put the Japanese recipe first. Here is a self-contained example for typesetting Japanese with LuaLaTeX (which sets Japanese via luatexja/ltjsclasses, needing neither a .latexmkrc nor dvipdfmx):

settings.json
{
  "latex-workshop.latex.tools": [
    {
      "name": "lualatexmk",
      "command": "latexmk",
      "args": [
        "-synctex=1",
        "-interaction=nonstopmode",
        "-file-line-error",
        "-lualatex",
        "-outdir=%OUTDIR%",
        "%DOC%"
      ],
      "env": {}
    }
  ],
  "latex-workshop.latex.recipes": [
    {
      "name": "lualatexmk",
      "tools": ["lualatexmk"]
    }
  ],
  "latex-workshop.latex.outDir": "%DIR%/out",
  "latex-workshop.latex.autoBuild.run": "onSave"
}

You can also put magic comments like % !TEX program = ... or % !TEX root = ... at the top of a file, and LaTeX Workshop honors them (disable via latex-workshop.latex.build.enableMagicComments). The recipe system is the recommended path today; % !TEX root earns its keep in multi-file projects, when you want to compile the main document while editing an included sub-file.

SyncTeX integration

SyncTeX records the correspondence between source lines and positions in the PDF (the -synctex=1 above writes that mapping into a .synctex.gz). It lets you keep your writing spot and the PDF view in sync, both ways. Using the built-in PDF viewer (viewer set to tab) is the smoothest, no-configuration path.

Forward search (source → PDF) jumps from your editing position to the matching spot in the PDF. The shortcut is **Ctrl+Alt+J (on Mac, Cmd+Option+J**); from the Command Palette it is “LaTeX Workshop: SyncTeX from cursor.” To run forward search automatically right after a build, set latex-workshop.synctex.afterBuild.enabled to true.

Inverse search (PDF → source) goes the other way, from a place in the PDF back to the matching source line. In the built-in tab viewer, **Ctrl-click (Cmd-click on Mac)** in the PDF moves the cursor to that line. The click style is set by latex-workshop.view.pdf.internal.synctex.keybinding, either ctrl-click (default) or double-click. Learn the forward/inverse pair together and you can hop to the right place instantly, even in a long document.

For SyncTeX in Japanese, two things suffice: pass -synctex=1 to $latex in your .latexmkrc (already done in the example above), and know that even via DVI ($pdf_mode = 3), upLaTeX + dvipdfmx carries the SyncTeX data through. SyncTeX with an external viewer (latex-workshop.view.pdf.external.synctex.*) needs more configuration, so the built-in tab is the recommended place to start.