← Back to list

Setting Up Copilot in NeoVim (LazyVim Example)

Important before following the steps below please take note of the following: On April 24 they will start using GitHub Copilot interaction…

j.xcvii · 2026-04-11 05:02 · 1 claps · 11.3 min read
#github-copilot #neovim #lazyvim #autocomplete
Open on Medium ↗
Wiki topics: LLM · Large Language Models 🔓 · Open Source

Setting Up Copilot in NeoVim (LazyVim Example)

Important before following the steps below please take note of the following: On April 24 they will start using GitHub Copilot interaction data for AI model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.

[Main Source: https://github.com/github/copilot.vim]

I don’t do agentic coding because I’m not ass at my job or at least I have not found the right tools to replace myself yet and drift away while the machine overlords subjugate us

Forewarned do not read the following Wikipedia page if you believe computational output can equal consciousness!

[Problem: https://en.wikipedia.org/wiki/Roko%27s_basilisk]

Another possibility is that we will rely so heavily on AI slop that our world will turn into idiocracy [https://en.wikipedia.org/wiki/Idiocracy]

I don’t want to digress however something that is nice is getting a helpful suggestion or a quick autocomplete so you can just superkey / down arrow and tab for auto completion for last bit of your function that you are missing or variable assignment.

I do most of my coding in NeoVim using LazyVim setup because it just looks nice and has everything that I need with minimal modifications needed for my workflow.

So how can you go about adding copilot or claude code or whatever code assistant that floats your boat in LazyVim. Go to the Lua directory and find the plugin path, path should look something like this [~/.config/nvim/lua] :

Under the plugins directory create a .lua file. The common convention is to name it after the package name. So in this case I called it copilot.lua.

Not all plugins require a setup or a configuraiton some you can just download the package from the repo and not pass in anything else example:

return
{
  {
"author"/"random-package",
  }
}

However at least for copilot that is not the case. As per the Github repo you need to pass in a function that has a setup method if you leave the method blank it will use the default settings however the function still needs to be passed in with the method.

The following is an example of the copilot.lua file needed to get started with the copilot plugin for NeoVim:

 return {
  {
    "github/copilot.vim",
    cmd = "Copilot",
    event = "InsertEnter",
    config = function()
      require("copilot").setup({
        panel = {
          enabled = true,
          auto_refresh = true,
          keymap = {
            jump_prev = "[[",
            jump_next = "]]",
            accept = "<CR>",
            refresh = "gr",
            open = "<M-CR>",
          },
          layout = {
            position = "bottom", -- | top | left | right | bottom |
            ratio = 0.4,
          },
        },
        suggestion = {
          enabled = true,
          auto_trigger = false,
          hide_during_completion = true,
          debounce = 15,
          trigger_on_accept = true,
          keymap = {
            accept = "<M-l>",
            accept_word = false,
            accept_line = false,
            next = "<M-]>",
            prev = "<M-[>",
            dismiss = "<C-]>",
            toggle_auto_trigger = false,
          },
        },
        nes = {
          enabled = false, -- requires copilot-lsp as a dependency
          auto_trigger = false,
          keymap = {
            accept_and_goto = false,
            accept = false,
            dismiss = false,
          },
        },
        auth_provider_url = nil, -- URL to authentication provider, if not "https://github.com/"
        logger = {
          file = vim.fn.stdpath("log") .. "/copilot-lua.log",
          file_log_level = vim.log.levels.OFF,
          print_log_level = vim.log.levels.WARN,
          trace_lsp = "off", -- "off" | "debug" | "verbose"
          trace_lsp_progress = false,
          log_lsp_messages = false,
        },
        copilot_node_command = "node", -- Node.js version must be > 22
        workspace_folders = {},
        copilot_model = "",
        disable_limit_reached_message = false, -- Set to `true` to suppress completion limit reached popup
        root_dir = function()
          return vim.fs.dirname(vim.fs.find(".git", { upward = true })[1])
        end,
        should_attach = function(buf_id, _)
          if not vim.bo[buf_id].buflisted then
            logger.debug("not attaching, buffer is not 'buflisted'")
            return false
          end
          if vim.bo[buf_id].buftype ~= "" then
            logger.debug("not attaching, buffer 'buftype' is " .. vim.bo[buf_id].buftype)
            return false
          end
          return true
        end,
        server = {
          type = "nodejs", -- "nodejs" | "binary"
          custom_server_filepath = nil,
        },
        server_opts_overrides = {},
      })
    end,
  },
}

Then you can just save and reopen NeoVim, your plugin should be installed but it will not work until you run the command that was specified in the code above :Copilot.

Once copilot is running, run :Copilot auth to start the authentication process.

Once your logged in you should be able to start seeing suggestions from Copilot when you are writing your code:

You can find further details on the Github repo [ https://github.com/github/copilot.vim] or below I leave you the comprehensive content for other commands / information required in your setup which as mentioned previously can be found in the Github Repo:


TABLE OF CONTENTS                      *copilot-copilot.lua-table-of-contents*

- |copilot-requirements|
- |copilot-install|
    - |copilot-authentication|
        - |copilot-authentication-with-alternate-github-instances|
- |copilot-setup-and-configuration|
    - |copilot-panel|
    - |copilot-suggestion|
    - |copilot-highlight-groups|
    - |copilot-filetypes|
    - |copilot-logger|
    - |copilot-copilot_node_command|
    - |copilot-server_opts_overrides|
    - |copilot-workspace_folders|
    - |copilot-root_dir|
    - |copilot-should_attach|
    - |copilot-server|
- |copilot-commands|
- |copilot-integrations|
- |copilot-faq|

REQUIREMENTS                                *copilot-copilot.lua-requirements*

- Curl
- NeoVim 0.11.0 or higher
- NodeJS v22 or higher if using the default nodejs LSP version

INSTALL                                          *copilot-copilot.lua-install*

Install the plugin with your preferred plugin manager. For example, with
packer.nvim <https://github.com/wbthomason/packer.nvim>:

>lua
    use { "zbirenbaum/copilot.lua"
      requires = {
        "copilotlsp-nvim/copilot-lsp", -- (optional) for NES functionality
      },
    }
<

AUTHENTICATION ~

You can authenticate using one of the following methods:

Permanent sign-in (Recommended) ~

Once copilot is running, run `:Copilot auth` to start the authentication
process.

Token (not officially supported) ~

Tokens given by `gh auth token` do not support Copilot, you therefore need to
first generate a token through the LSP by:

- Authenticating using the `Permanent sign-in` method
- Grab the token by running `:Copilot auth info`
- You can then safely delete the `github-copilot` folder created in your NeoVim base data directory.

Set either the environment variable `GITHUB_COPILOT_TOKEN` or
`GH_COPILOT_TOKEN` to that token. Note that if you have the variable set, even
empty, the LSP will attempt to use it to log in.

Sign out / Switch accounts ~

To sign out of your current GitHub account:

>
    :Copilot auth signout
<

To sign in with a different account:

>
    :Copilot auth signin
<

To view your current authentication token information:

>
    :Copilot auth info
<

Credentials are stored in: - **Linux/macOS:**
`~/.config/github-copilot/apps.json` (or
`$XDG_CONFIG_HOME/github-copilot/apps.json`) - **Windows:**
`~/AppData/Local/github-copilot/apps.json`

AUTHENTICATION WITH ALTERNATE GITHUB INSTANCES

If your access to Copilot is not provided by the public GitHub instance, you
can set your authentication provider to a custom URL with the corresponding
config key e.g. `auth_provider_url = "https://mycorp.ghe.com/"`.

SETUP AND CONFIGURATION          *copilot-copilot.lua-setup-and-configuration*

You have to run the `require("copilot").setup(options)` function in order to
start Copilot. If no options are provided, the defaults are used.

Because the copilot server takes some time to start up, it is recommended that
you lazy load copilot. For example:

>lua
    use {
      "zbirenbaum/copilot.lua",
      requires = {
        "copilotlsp-nvim/copilot-lsp", -- (optional) for NES functionality
      },
      cmd = "Copilot",
      event = "InsertEnter",
      config = function()
        require("copilot").setup({})
      end,
    }
<

Default configuration ~

>lua
    require('copilot').setup({
      panel = {
        enabled = true,
        auto_refresh = false,
        keymap = {
          jump_prev = "[[",
          jump_next = "]]",
          accept = "<CR>",
          refresh = "gr",
          open = "<M-CR>"
        },
        layout = {
          position = "bottom", -- | top | left | right | bottom |
          ratio = 0.4
        },
      },
      suggestion = {
        enabled = true,
        auto_trigger = false,
        hide_during_completion = true,
        debounce = 15,
        trigger_on_accept = true,
        keymap = {
          accept = "<M-l>",
          accept_word = false,
          accept_line = false,
          next = "<M-]>",
          prev = "<M-[>",
          dismiss = "<C-]>",
          toggle_auto_trigger = false,
        },
      },
      nes = {
        enabled = false, -- requires copilot-lsp as a dependency
        auto_trigger = false,
        keymap = {
          accept_and_goto = false,
          accept = false,
          dismiss = false,
        },
      },
      auth_provider_url = nil, -- URL to authentication provider, if not "https://github.com/"
      logger = {
        file = vim.fn.stdpath("log") .. "/copilot-lua.log",
        file_log_level = vim.log.levels.OFF,
        print_log_level = vim.log.levels.WARN,
        trace_lsp = "off", -- "off" | "debug" | "verbose"
        trace_lsp_progress = false,
        log_lsp_messages = false,
      },
      copilot_node_command = 'node', -- Node.js version must be > 22
      workspace_folders = {},
      copilot_model = "",
      disable_limit_reached_message = false,  -- Set to `true` to suppress completion limit reached popup
      root_dir = function()
        return vim.fs.dirname(vim.fs.find(".git", { upward = true })[1])
      end,
      should_attach = function(buf_id, _)
        if not vim.bo[buf_id].buflisted then
          logger.debug("not attaching, buffer is not 'buflisted'")
          return false
        end

        if vim.bo[buf_id].buftype ~= "" then
          logger.debug("not attaching, buffer 'buftype' is " .. vim.bo[buf_id].buftype)
          return false
        end

        return true
      end,
      server = {
        type = "nodejs", -- "nodejs" | "binary"
        custom_server_filepath = nil,
      },
      server_opts_overrides = {},
    })
<

PANEL ~

Panel can be used to preview suggestions in a split window. You can run the
`:Copilot panel` command to open it.

If `auto_refresh` is `true`, the suggestions are refreshed as you type in the
buffer.

The `copilot.panel` module exposes the following functions:

>lua
    require("copilot.panel").accept()
    require("copilot.panel").jump_next()
    require("copilot.panel").jump_prev()
    require("copilot.panel").open({position, ratio})
    require("copilot.panel").close()
    require("copilot.panel").toggle()
    require("copilot.panel").refresh()
    require("copilot.panel").is_open()
<

These can also be accessed through the `:Copilot panel <function>` command (eg.
`:Copilot panel accept`).

SUGGESTION ~

When `auto_trigger` is `true`, copilot starts suggesting as soon as you enter
insert mode. When `auto_trigger` is `false`, use the `next`, `prev` or `accept`
keymap to trigger copilot suggestion. When `trigger_on_accept` is `false`, the
keypress will be passed to the buffer as-is, instead of triggering completion.

To toggle auto trigger for the current buffer, use
`require("copilot.suggestion").toggle_auto_trigger()`.

Copilot suggestion is automatically hidden when `popupmenu-completion` is open.
In case you use a custom menu for completion, you can set the
`copilot_suggestion_hidden` buffer variable to `true` to have the same
behavior.

Example using nvim-cmp ~

>lua
    cmp.event:on("menu_opened", function()
      vim.b.copilot_suggestion_hidden = true
    end)

    cmp.event:on("menu_closed", function()
      vim.b.copilot_suggestion_hidden = false
    end)
<

Example using blink.cmp ~

>lua
    vim.api.nvim_create_autocmd("User", {
      pattern = "BlinkCmpMenuOpen",
      callback = function()
        vim.b.copilot_suggestion_hidden = true
      end,
    })

    vim.api.nvim_create_autocmd("User", {
      pattern = "BlinkCmpMenuClose",
      callback = function()
        vim.b.copilot_suggestion_hidden = false
      end,
    })
<

The `copilot.suggestion` module exposes the following functions:

>lua
    require("copilot.suggestion").is_visible()
    require("copilot.suggestion").accept(modifier)
    require("copilot.suggestion").accept_word()
    require("copilot.suggestion").accept_line()
    require("copilot.suggestion").next()
    require("copilot.suggestion").prev()
    require("copilot.suggestion").clear_preview()
    require("copilot.suggestion").update_preview()
    require("copilot.suggestion").dismiss()
    require("copilot.suggestion").toggle_auto_trigger()
<

These can also be accessed through the `:Copilot suggestion <function>` command
(eg. `:Copilot suggestion accept`).

HIGHLIGHT GROUPS ~

Copilot uses two highlight groups to style its suggestions:

  -----------------------------------------------------------------------
  Highlight Group         Used For                Default Link
  ----------------------- ----------------------- -----------------------
  CopilotSuggestion       Inline ghost text       Comment
                          suggestions             

  CopilotAnnotation       Annotations in the      Comment
                          panel and inline        
                          suggestions             
  -----------------------------------------------------------------------
If these highlight groups are not defined by your colorscheme, they will
default to linking to `Comment`. To customize them, set the highlights
**after** your colorscheme loads, or use a `ColorScheme` autocmd:

>lua
    vim.api.nvim_create_autocmd("ColorScheme", {
      callback = function()
        vim.api.nvim_set_hl(0, "CopilotSuggestion", { fg = "#83a598", italic = true })
        vim.api.nvim_set_hl(0, "CopilotAnnotation", { fg = "#83a598" })
      end,
    })
<

NES (NEXT EDIT SUGGESTION) ~

  [!WARNING] This feature is still experimental and may not work as expected in
  all scenarios, please report any issues you encounter.
When `enabled` is `true`, copilot will provide suggestions based on the next
edit you are likely to make, through copilot-lsp
<https://github.com/copilotlsp-nvim/copilot-lsp>. If there is no suggestion,
the keymaps will pass through the original keymap.

`copilot-lsp` has a few configurations built-in as well, for additional
configurations, please refer to the copilot-lsp documentation
<https://github.com/copilotlsp-nvim/copilot-lsp/blob/main/README.md>. These
configurations should be set in the `init` function of the `copilot-lsp`
dependency.

>lua
    use {
      "zbirenbaum/copilot.lua",
      requires = {
        "copilotlsp-nvim/copilot-lsp",
        init = function()
          vim.g.copilot_nes_debounce = 500
        end,
      },
      cmd = "Copilot",
      event = "InsertEnter",
      config = function()
        require("copilot").setup({
          nes = {
            enabled = true,
            keymap = {
              accept_and_goto = "<leader>p",
              accept = false,
              dismiss = "<Esc>",
            },
          },
        })
      end,
    }
<

FILETYPES ~

Specify filetypes for attaching copilot.

Example:

>lua
    require("copilot").setup {
      filetypes = {
        markdown = true, -- overrides default
        terraform = false, -- disallow specific filetype
        sh = function ()
          if string.match(vim.fs.basename(vim.api.nvim_buf_get_name(0)), '^%.env.*') then
            -- disable for .env files
            return false
          end
          return true
        end,
      },
    }
<

If you add `"*"` as a filetype, the default configuration for `filetypes`
won’t be used anymore. e.g.

>lua
    require("copilot").setup {
      filetypes = {
        javascript = true, -- allow specific filetype
        typescript = true, -- allow specific filetype
        ["*"] = false, -- disable for all other filetypes and ignore default `filetypes`
      },
    }
<

LOGGER ~

Logs will be written to the `file` for anything of `file_log_level` or higher.
Logs will be printed to NeoVim (using `notify`) for anything of
`print_log_level` or higher. To turn either off, simply set its level to
`vim.log.levels.OFF`. File logging is done asynchronously to minimize
performance impacts, however there is still some overhead.

Log levels used are the ones defined in `vim.log`:

>lua
    vim.log = {
      levels = {
        TRACE = 0,
        DEBUG = 1,
        INFO = 2,
        WARN = 3,
        ERROR = 4,
        OFF = 5,
      },
    }
<

`trace_lsp` controls logging of LSP trace messages (`$/logTrace`) can either
be:

- `off`
- `messages` which will output the LSP messages
- `verbose` which adds additional information to the message.

When `trace_lsp_progress` is true, LSP progress messages (`$/progress`) will
also be logged. When `log_lsp_messages` is true, LSP log messages
(`window/logMessage`) events will be logged.

Careful turning on all logging features as the log files may get very large
over time, and are not pruned by the application.

COPILOT_NODE_COMMAND ~

Use this field to provide the path to a specific node version such as one
installed by nvm. Node.js version must be 22 or newer.

Example:

>lua
    copilot_node_command = vim.fn.expand("$HOME") .. "/.config/nvm/versions/node/v22.0.0/bin/node", -- Node.js version must be > 22
<

SERVER_OPTS_OVERRIDES ~

Override copilot lsp client settings. See |vim.lsp.start| for the list of
options. Ensure that the `name` field is not overridden as it is used for
efficiency reasons in numerous checks to verify copilot is actually running.

The `settings` field is where you can customize the copilot lsp behavior. See
SettingsOpts.md <./SettingsOpts.md> for the full list of available settings and
their keys.

Example:

>lua
    require("copilot").setup {
      server_opts_overrides = {
        trace = "verbose",
        settings = {
          advanced = {
            listCount = 10, -- #completions for panel
            inlineSuggestCount = 3, -- #completions for getCompletions
          }
        },
      }
    }
<

  [!NOTE] The `settings` values follow a nested table structure matching the keys
  in SettingsOpts.md <./SettingsOpts.md>. For example, `InlineSuggestCount:
  ["advanced", "inlineSuggestCount"]` becomes `settings = { advanced = {
  inlineSuggestCount = 3 } }`.

WORKSPACE_FOLDERS ~

Workspace folders improve Copilot’s suggestions. By default, the root_dir is
used as a workspace_folder.

Additional folders can be added through the configuration as such:

>lua
    workspace_folders = {
      "/home/user/gits",
      "/home/user/projects",
    }
<

They can also be added runtime, using the command `:Copilot workspace add
[folderpath]` where `[folderpath]` is the workspace folder.

ROOT_DIR ~

This allows changing the function that gets the root folder, the default looks
for a parent folder that contains the folder `.git`. If none is found, it will
use the current working directory.

SHOULD_ATTACH ~

This function is called to determine if copilot should attach to the buffer or
not. It is useful if you would like to go beyond the filetypes and have more
control over when copilot should attach. You can also use it to attach to
buflisted buffers by simply omitting that portion from the function. Since this
happens before attaching to the buffer, it is good to prevent Copilot from
reading sensitive files.

An example of this would be:

>lua
    require("copilot").setup {
      should_attach = function(_, bufname)
        if string.match(bufname, "env") then
          return false
        end

        return true
      end
    }
<

SERVER ~

  [!CAUTION] `"binary"` mode is still very much experimental, please report any
  issues you encounter.
`type` can be either `"nodejs"` or `"binary"`. The binary version will be
downloaded if used.

`custom_server_filepath` is used to specify the server path (filename included)
of either the `js` file if using `"nodejs"` or to the binary if using
`"binary"`. The filename on its own can also be set if accessible through your
PATH. When using `"binary"`, the download process will be disabled and the
binary will be used directly. example:

>lua
    require("copilot").setup {
      server = {
        type = "nodejs",
        custom_server_filepath = "/home/user/copilot-lsp/language-server.js",
      },
    }
<

COMMANDS                                        *copilot-copilot.lua-commands*

`copilot.lua` defines the `:Copilot` command that can perform various actions.
It has completion support, so try it out.

INTEGRATIONS                                *copilot-copilot.lua-integrations*

The `copilot.api` module can be used to build integrations on top of
`copilot.lua`.

- zbirenbaum/copilot-cmp <https://github.com/zbirenbaum/copilot-cmp>: Integration with `nvim-cmp` <https://github.com/hrsh7th/nvim-cmp>.
- giuxtaposition/blink-cmp-copilot <https://github.com/giuxtaposition/blink-cmp-copilot>: Integration with `blink.cmp` <https://github.com/Saghen/blink.cmp>.
- fang2hou/blink-copilot <https://github.com/fang2hou/blink-copilot>: Integration with `blink.cmp` <https://github.com/Saghen/blink.cmp>, with some differences.
- AndreM222/copilot-lualine <https://github.com/AndreM222/copilot-lualine>: Integration with `lualine.nvim` <https://github.com/nvim-lualine/lualine.nvim>.

FAQ                                                  *copilot-copilot.lua-faq*

  Certificate Parsing Error
This is an issue with the copilot lsp itself as described in this discussion
<https://github.com/orgs/community/discussions/136273#discussioncomment-10433527>.
Please update the plugin to the latest version to solve this issue. If updating
does not help, some users have reported that updating the
`/usr/bin/update-ca-trust` and removing the –comment option from the trust
extract commands solves the issue. However this has not been verified by the
author of this plugin and may have unintended consequences so thread with care.

  Multiple offset encodings warning
As discussed in #247, the problem arises because two or more clients are using
different offset encodings. To solve this, in lspconfig:

>lua
    local capabilities = vim.lsp.protocol.make_client_capabilities() -- Get The capabilities
    capabilities.general.positionEncodings = { "utf-16" } -- Set the offset encoding, see `:h vim.lsp.start` for more info
    require("lspconfig")[server].setup({ capabilities = capabilities }) -- Setup the server
<

Set the same for copilot in `server_opts_overrides`:

>lua
    server_opts_overrides = {
      offset_encoding = "utf-16" -- Set the offset encoding same as above, see `:h vim.lsp.start` for more info
    }
<

Refer to your plugins documentation for changes.

==============================================================================
2. Links                                                       *copilot-links*

1. *@tris203*: 

Generated by panvimdoc <https://github.com/kdheepak/panvimdoc>

vim:tw=78:ts=8:noet:ft=help:norl:

메타데이터
post_id
38b0ea2f7896
slug
setting-up-copilot-in-neovim-lazyvim-example-38b0ea2f7896
url
https://medium.com/@jayarch/setting-up-copilot-in-neovim-lazyvim-example-38b0ea2f7896
canonical_url
https://medium.com/@jayarch/setting-up-copilot-in-neovim-lazyvim-example-38b0ea2f7896
author_url
https://medium.com/@jayarch
status
ok
fetched_at
2026-07-15 13:32:53