Install, configure, and use AI-powered code completion — from first setup to daily use.
GitHub Copilot is an AI code completion tool that suggests entire lines or blocks of code as you type, based on context from your current file and comments. In Neovim, suggestions appear as greyed-out ghost text — press Tab to accept or keep typing to ignore.
Free or paid plan activated at github.com/settings/copilot.
Required by the language server backend. Check with node --version.
copilot.lua requires 0.9+. The official copilot.vim works from 0.6+.
Examples below use lazy.nvim. Adapt as needed for packer or other managers.
There are two plugins to choose from. copilot.lua is recommended for modern Neovim setups — it is written in pure Lua and integrates cleanly with nvim-cmp.
-- lazy.nvim
{
"zbirenbaum/copilot.lua",
cmd = "Copilot",
event = "InsertEnter",
opts = {
suggestion = {
enabled = true,
auto_trigger = true,
keymap = {
accept = "<Tab>",
accept_word = "<C-Right>",
next = "<M-]>",
prev = "<M-[>",
dismiss = "<C-]>",
},
},
panel = { enabled = false },
},
},
-- lazy.nvim
{
"github/copilot.vim",
-- keymaps are set automatically:
-- Tab → accept
-- Ctrl+] → dismiss
-- Alt+] / Alt+[ → next/prev
}
copilot.vim maps Tab globally in insert mode, which often conflicts with snippet and completion plugins. See the Tab section below.
:Copilot setupNeovim prints a one-time device code and opens (or tells you to open) github.com/login/device.
Paste the code shown in Neovim into the GitHub device page and click Authorise GitHub Copilot.
:Copilot statusShould print Copilot: Ready. If not, confirm Node.js is on your PATH (node --version) and your subscription is active.
After a brief pause while typing, Copilot sends your file context to GitHub's servers and streams back a suggestion, shown as ghost text after your cursor.
The suggestion appears inline in grey. Press Tab to accept the full suggestion or Ctrl+Right to accept word by word.
Copilot generates several alternatives. Cycle through them with Alt+] / Alt+[. Press Ctrl+] to dismiss all.
Copilot reads the content of your current file, open buffers, and comments. Descriptive comments and function signatures give better results.
Run :Copilot panel (copilot.vim) to open a split showing up to 10 alternative completions at once.
| Tab | Accept full suggestion |
| Ctrl+Right | Accept next word only (copilot.lua) |
| Ctrl+Alt+] | Accept next word only (copilot.vim) |
| Alt+] | Next suggestion |
| Alt+[ | Previous suggestion |
| Ctrl+] | Dismiss suggestion |
| :Copilot setup | Authenticate with GitHub |
| :Copilot status | Check connection status |
| :Copilot enable | Enable globally |
| :Copilot disable | Disable globally |
| :Copilot panel | Open alternatives panel |
Add copilot-cmp to surface Copilot suggestions inside the nvim-cmp popup menu alongside LSP and snippet completions.
-- lazy.nvim — add alongside copilot.lua
{
"zbirenbaum/copilot-cmp",
dependencies = "zbirenbaum/copilot.lua",
config = true,
},
-- In your cmp config, add "copilot" as a source:
require("cmp").setup({
sources = cmp.config.sources({
{ name = "copilot", group_index = 2 },
{ name = "nvim_lsp", group_index = 2 },
{ name = "luasnip", group_index = 2 },
{ name = "buffer", group_index = 3 },
}),
})
suggestion = { enabled = false } in your copilot.lua opts.
Copilot, LuaSnip, and nvim-cmp all compete for Tab. This mapping checks each in priority order and falls back to a literal tab.
vim.keymap.set("i", "<Tab>", function()
local copilot = require("copilot.suggestion")
local luasnip = require("luasnip")
if copilot.is_visible() then
copilot.accept()
elseif luasnip.expand_or_jumpable() then
luasnip.expand_or_jump()
else
return "<Tab>"
end
end, { expr = true, silent = true })
-- In copilot.lua opts:
filetypes = {
markdown = false, -- avoid leaking prose
yaml = false,
[".env"] = false, -- never suggest in env files
["*"] = true, -- enable everywhere else
},
.env files, secrets, and private configs. File contents are sent to GitHub's API with each request.
A comment like -- parse ISO date string and return table produces far better completions than an empty function body.
Copilot infers intent from variable and function names. parseUserInput produces more relevant suggestions than foo.
Copilot uses open buffers as context. Keeping interface or type definition files open helps it match your project's patterns.
:Copilot panel shows up to 10 alternatives at once — useful when you want to see different approaches to a problem.