# Gopls: Setting up your workspace

In the language server protocol, a "workspace" consists of a folder along with
per-folder configuration. Some LSP clients such as VS Code allow configuring
workspaces explicitly, while others do so automatically by looking for special
files defining a workspace root (such as a `.git` directory or `go.mod` file).

In order to function, gopls needs a defined scope in which language features
like references, rename, and implementation should operate. Put differently,
gopls needs to infer from the LSP workspace which  `go build` invocations you
would use to build your workspace, including the working directory,
environment, and build flags.

In the past, it could be tricky to set up your workspace so that gopls would
infer the correct build information. It required opening the correct directory
or using a `go.work` file to tell gopls about the modules you're working on,
and configuring the correct operating system and architecture in advance.
When this didn't work as expected, gopls would often fail in mysterious
ways--the dreaded "No packages found" error.

Starting with gopls v0.15.0, workspace configuration is much simpler, and gopls
will typically work when you open a Go file anywhere in your workspace. If it
isn't working for you, or if you want to better understand how gopls models
your workspace, please read on.

## Workspace builds

Starting with gopls v0.15.0, gopls will guess the builds you are working on
based on the set of open files. When you open a file in a workspace folder,
gopls checks whether the file is contained in a module, `go.work` workspace, or
GOPATH directory, and configures the build accordingly. Additionally, if you
open a file that is constrained to a different operating system or
architecture, for example opening `foo_windows.go` when working on Linux, gopls
will create a scope with `GOOS` and `GOARCH` set to a value that matches the
file.

For example, suppose we had a repository with three modules: `moda`, `modb`,
and `modc`, and a `go.work` file using modules `moda` and `modb`. If we open
the files `moda/a.go`, `modb/b.go`, `moda/a_windows.go`, and `modc/c.go`, gopls
will automatically create three builds:

![Zero Config gopls](zeroconfig.png)

This allows gopls to _just work_ when you open a Go file, but it does come with
several caveats:

- It causes gopls to do more work, since it is now tracking three builds
  instead of one. However, the recent
  [scalability redesign](https://go.dev/blog/gopls-scalability)
  allows much of this work to be avoided through efficient caching.
- For operations invoked from a given file, such as "References"
  or "Implementations", gopls executes the operation in
  _the default build for that file_. For example, finding references to
  a symbol `S` from `foo_linux.go` will return references from the Linux build,
  and finding references to the same symbol `S` from `foo_windows.go` will
  return references from the Windows build. Gopls searches the default build
  for the file, but it doesn't search all the other possible builds (even
  though that would be nice) because it is liable to be too expensive.
  Issues [#65757](https://go.dev/issue/65757) and
  [#65755](https://go.dev/issue/65755) propose improvements to this behavior.
- When selecting a `GOOS/GOARCH` combination to match a build-constrained file,
  gopls will choose the first matching combination from
  [this list](https://cs.opensource.google/go/x/tools/+/master:gopls/internal/cache/port.go;l=30;drc=f872b3d6f05822d290bc7bdd29db090fd9d89f5c).
  In some cases, that may be surprising.
- When working in a `GOOS/GOARCH` constrained file that does not match your
  default toolchain, `CGO_ENABLED=0` is implicitly set, since a C toolchain for
  that target is unlikely to be available. This means that gopls will not
  work in files including `import "C"`. Issue
  [#65758](https://go.dev/issue/65758) may lead to improvements in this
  behavior.
- Gopls is currently unable to guess build flags that include arbitrary
  user-defined build constraints, such as a file with the build directive
  `//go:build mytag`. Issue [#65089](https://go.dev/issue/65089) proposes
  a heuristic by which gopls could handle this automatically.

Please provide feedback on this behavior by upvoting or commenting the issues
mentioned above, or opening a [new issue](https://go.dev/issue/new) for other
improvements you'd like to see.

## When to use a `go.work` file for development

Starting with Go 1.18, the `go` command has built-in support for multi-module
workspaces specified by [`go.work`](https://go.dev/ref/mod#workspaces) files.
Gopls will recognize these files if they are present in your workspace.

Use a `go.work` file when:

- you want to work on multiple modules simultaneously in a single logical
  build, for example if you want changes to one module to be reflected in
  another.
- you want to improve gopls' memory usage or performance by reducing the number
  of builds it must track.
- you want gopls to know which modules you are working on in a multi-module
  workspace, without opening any files. For example, it may be convenient to use
  `workspace/symbol` queries before any files are open.
- you are using gopls v0.14.2 or earlier, and want to work on multiple
  modules.

For example, suppose this repo is checked out into the `$WORK/tools` directory,
and [`x/mod`](https://pkg.go.dev/golang.org/x/mod) is checked out into
`$WORK/mod`, and you are working on a new `x/mod` API for editing `go.mod`
files that you want to simultaneously integrate into gopls.

You can work on both `golang.org/x/tools/gopls` and `golang.org/x/mod`
simultaneously by creating a `go.work` file:

```sh
cd $WORK
go work init
go work use tools/gopls mod
```

then opening the `$WORK` directory in your editor.

## When to manually configure `GOOS`, `GOARCH`, or `-tags`

As described in the first section, gopls v0.15.0 and later will try to
configure a new build scope automatically when you open a file that doesn't
match the system default operating system (`GOOS`) or architecture (`GOARCH`).

However, per the caveats listed in that section, this automatic behavior comes
with limitations. Customize your gopls environment by setting `GOOS` or
`GOARCH` in your
[`"build.env"`](https://github.com/golang/tools/blob/master/gopls/doc/settings.md#env)
or `-tags=...` in your"
["build.buildFlags"](https://github.com/golang/tools/blob/master/gopls/doc/settings.md#buildflags)
when:

- You want to modify the default build environment.
- Gopls is not guessing the `GOOS/GOARCH` combination you want to use for
  cross platform development.
- You need to work on a file that is constrained by a user-defined build tags,
  such as the build directive `//go:build mytag`.

## GOPATH mode

When opening a directory within a `GOPATH` directory, the workspace scope will
be just that directory and all directories contained within it. Note that
opening a large GOPATH directory can make gopls very slow to start.
