The Go Programming Language
go-legacy-win7 is a fork of the Go programming language that maintains support for Windows 7, 8, 8.1, Server 2008 R2, Server 2012, and Server 2012 R2, and restores the deprecated go get behaviour. This project aims to provide a stable Go environment for users who need to support legacy Windows systems or prefer the traditional Go workflow.
Gopher image by Renee French, licensed under Creative Commons 4.0 Attribution licence.
Differences from Upstream Go
-
Windows 7/8/8.1 and Legacy Server Support
While the official Go project dropped support for Windows 7, 8, 8.1, Server 2008 R2, Server 2012, and Server 2012 R2 in Go 1.21, this fork maintains compatibility with all these legacy Windows systems.Tested on Windows 7 (build 7600) — no updates required — through Windows 11 26H2 (build 26300)
-
Upstream Code First, Not a Blind Revert
Legacy support is not restored by reverting upstream changes or freezing old code. Upstream's current implementation is kept, with a fallback beneath it chosen at runtime by what the machine actually supports. Each fallback is built to reproduce upstream's behaviour as closely as the platform allows, so a program behaves the same whether it runs on Windows 7 or Windows 11, and current Windows is unaffected. -
Classic
go getBehaviour
This fork allows for the deprecatedgo getbehaviour whenGO111MODULEis set to "off" or "auto". This means:- In
GOPATH/src,go getandgo installcan operate inGOPATHmode. - Outside of
GOPATH/src, these commands can use module-aware mode when appropriate.
- In
-
Compatibility Notes
Please be aware that some newer Go features may not be fully compatible with legacy Windows systems. We try to maintain as much functionality as possible, but some limitations may exist. If you find one, please report it.
Changes in Each Release
Current release includes the following modifications. The last column names the upstream change each patch works around and the Go release it shipped in, or the kernel where there is none. The T patches touch tests only.
Loader and startup
| What it fixes | Patch | Upstream change |
|---|---|---|
Binaries built by stock Go 1.27 do not start on Windows 7, 8 or 8.1. Upstream stamps a Windows 10 minimum version into every PE image. The fork stamps 6.1, and syscall.GetVersion reads the true version so that the compatibility shim cannot report Windows 8 to it. | 0001 | 341b5e2 (Go 1.27) |
Every program dies at startup on Windows 7 without KB2533623. The runtime and syscall load system DLLs with a search flag that update introduced. Where the flag is rejected they load the file by its full path in the system directory. | 0002 | a17d959 (Go 1.21) |
Every program dies at startup on Windows 7, which has no ProcessPrng. The runtime and crypto/rand fall back to RtlGenRandom where it is missing. | 0003 | 693def1 (Go 1.22, and 1.21.5 by backport) |
Processes and consoles
| What it fixes | Patch | Upstream change |
|---|---|---|
Starting a child process from a console fails on Windows 7, the go command included. Windows 7 console handles are not real handles. StartProcess treats them as Go 1.21 did. | 0004 | 2d76081 (Go 1.17) 48042aa (Go 1.22) |
Opening or stating CON, CONIN$ or CONOUT$ fails on Windows 7. The \\.\ names reach the console only from Windows 8. os retries with the bare names. | 0006 | 28b8851 (Go 1.23) bb0c14b (Go 1.25) |
Network and the poller
| What it fixes | Patch | Upstream change |
|---|---|---|
Every socket creation fails on Windows 7 (build 7600). WSA_FLAG_NO_HANDLE_INHERIT needs Service Pack 1. net retries without it and clears inheritance afterwards. | 0007 | 7c1157f (Go 1.22) |
File on a connection or listener fails before Windows 8.1. Nothing before 8.1 can take a handle off a completion port. The handle is left where it is and still works, and Close still ends a pending read on it. | 0008 | 8a8f506 (Go 1.25) 6953ef8 (Go 1.25) |
| A UDP read into a buffer too small for a datagram already queued hangs forever on Windows 7. Datagram sockets no longer skip the completion packet there. | 0009 | 932d0ae (Go 1.21) |
os.File.Fd cannot hand back a detached handle before Windows 8.1. Files and pipes are kept off the runtime's completion port there, with deadlines of their own, so Fd returns a detached handle. | 0010 | 8a8f506 (Go 1.25) d889729 (Go 1.28, and 1.26.9 and 1.27.2 by backport) |
Every listener in the process stops accepting on Windows 8 and Server 2012 while a thread reads a pipe. The kernel holds an AcceptEx completion until the posting thread leaves synchronous I/O. AcceptEx is posted from a thread that never does. | 0018 | Connect #760161 (Windows 8) Kernel |
Files
| What it fixes | Patch | Upstream change |
|---|---|---|
Listing a directory fails on Windows 7 on FAT32, exFAT and network shares. The newer directory information class arrived in Windows 8. os reads with the older one where the kernel rejects the new. | 0005 | be0b8e8 (Go 1.22) 2860e01 (Go 1.23) |
os.RemoveAll leaves a read-only directory behind before Windows 10 1809. The read-only attribute is cleared on a directory as it is on a file. | 0011 | b31dc77 (Go 1.26) 6d41809 (Go 1.25) |
A deleted file keeps its name while another handle holds it, where the kernel has no POSIX delete. A held file is moved aside before it is marked, so the name is free at once, through os.Remove too. | 0012 | b31dc77 (Go 1.26) |
Deleting a program right after it exits fails on Windows 8 and 8.1. The kernel keeps the image mapped for a moment after Wait returns. The delete waits that out. | 0013 | f0894a0 (Go 1.22) |
os.RemoveAll finds a directory not empty while an entry already marked for deletion is on its way out. The delete waits for the name to go. | 0014 | b31dc77 (Go 1.26) Kernel |
| Renaming onto a link or a held file fails where the kernel has no POSIX rename. The target is moved aside, the rename retried, and the copy deleted. | 0015 | 2ffda87 (Go 1.25) |
| A junction or directory symlink to a file opens on Windows 7, 8 and 8.1 where Windows 10 refuses it. Links are held to their type on every Windows, so a program gets the same answer everywhere. | 0016 | b19851b (Go 1.28, and 1.26.9 and 1.27.2 by backport) Kernel |
Race detector
| What it fixes | Patch | Upstream change |
|---|---|---|
A -race binary does not start on Windows 7. The race runtime's address wait functions are defined by the fork and emulated where the kernel lacks them, and the Windows 8 import library is no longer linked. | 0017 | c3bea70 (Go 1.19) cc82867 (Go 1.21) |
The go command
| What it fixes | Patch | Upstream change |
|---|---|---|
go get in GOPATH mode is gone since Go 1.22. Restored, so GO111MODULE=off go get fetches into GOPATH/src and installs again. | 9999 | de4d503 (Go 1.22) |
Tests only
| What it fixes | Patch | Upstream change |
|---|---|---|
| A cgo callback test faults on Windows 7 (build 7600). It clobbers a register with an AVX instruction, which Windows 7 enables only from Service Pack 1. SSE2 does the same job. | T0001 | 52fd498 (Go 1.27) |
| The VHD tests pass on Windows 7 without testing anything. The Hyper-V cmdlets they need arrived with Windows 8. They skip where the cmdlets are missing. | T0002 | 7986e26 (Go 1.23) |
| A live TLS resumption test fails where the root store lacks the server's root. It skips when no dial verifies. | T0003 | b691a2e (Go 1.27, and 1.26.0 by backport) |
| The system certificate verification tests fail where the root store lacks GTS Root R1. Those cases skip. | T0004 | bb8f9a6 (Go 1.21) |
Test Results
Every fallback is coupled with tests, and the fork passes Go's test suite on each system below.
| System | Version | Toolchain | Go test suite |
|---|---|---|---|
| Windows 7 32-bit | 6.1.7600 | windows_386 | ✅ Passed |
| Windows 7 64-bit | 6.1.7600 | windows_amd64 | ✅ Passed |
| Windows 8 64-bit | 6.2.9200 | windows_amd64 | ✅ Passed |
| Windows 8.1 64-bit | 6.3.9600 | windows_amd64 | ✅ Passed |
| Windows 10 32-bit | 10.0.19045 | windows_386 | ✅ Passed |
| Windows 11 64-bit | 10.0.26300 | windows_amd64 | ✅ Passed |
On Windows 10 and 11 the fork matches stock Go.
32-bit builds are tested only on Windows 7 and 10. They behave the same as their 64-bit siblings on the same kernel.
Download and Install
Binary Distributions
Release archives do not include the tests and scripts. Clone the repo if you want to run them.
Before you begin
To avoid PATH/GOROOT conflicts and mixed toolchains, uninstall any existing Go installation first.
Windows Installation
- Download the
go-legacy-win7-<version>.windows_<arch>.zipfile. - Extract the ZIP to
C:\(or any preferred location). This will create ago-legacy-win7folder. - Add the following to your system environment variables:
- Add
C:\go-legacy-win7\bin(or your chosen path) to the systemPATH. - Set
GOROOTtoC:\go-legacy-win7(or your chosen path).
- Add
- Add the following to your user environment variables:
- Add
%USERPROFILE%\go\binto the userPATH. - Set
GOPATHto%USERPROFILE%\go.
- Add
macOS and Linux Installation
-
Download the appropriate
go-legacy-win7-<version>.<os>_<arch>.tar.gzfile.- For macOS:
go-legacy-win7-<version>.darwin_<arch>.tar.gz - For Linux:
go-legacy-win7-<version>.linux_<arch>.tar.gz
- For macOS:
-
Extract the archive to
/usr/local:sudo tar -C /usr/local -xzf go-legacy-win7-<version>.<os>_<arch>.tar.gz -
Add the following to your shell configuration file:
- For bash, add to
~/.bash_profileor~/.bashrc - For zsh, add to
~/.zshrc
export GOROOT=/usr/local/go-legacy-win7 export GOPATH=$HOME/go export PATH=$PATH:$GOROOT/bin:$GOPATH/bin - For bash, add to
-
Apply the changes:
- For bash:
source ~/.bash_profileorsource ~/.bashrc - For zsh:
source ~/.zshrc
Note:
- On macOS Catalina and later, zsh is the default shell.
- On most Linux distributions, bash is the default shell.
- For bash:
After installation, verify the installation by opening a new terminal and running:
go version
Install From Source
To install from source, please follow the steps on the official website.
FAQ
Is this official Go?
No. It is an independent fork. Bug reports for this fork belong here. Language and spec issues still belong with upstream Go.
Why not just use an old Go release?
Old releases miss years of fixes and language/runtime updates. This fork tracks current Go releases while retaining the legacy Windows and go get support.
Will you drop Windows 7 or raise system requirements?
No. Supporting Windows 7 and later is a standing promise. We aim to keep things working. We do not “fix” what is not broken.
What about security on legacy Windows?
Older Windows already has a large attack surface. Hardening individual legacy APIs here would not make those systems meaningfully safer. We prioritise stable behaviour instead, without weakening what upstream Go already guarantees. Prefer a Windows version Microsoft still supports when you can. This fork exists for cases where you cannot.
Is this safe to use on modern Windows?
Yes. The fork always prefers upstream's implementation and falls back only where the running system cannot provide it, so on current Windows you get exactly the APIs upstream Go uses. Neither side pays for the other. Legacy systems gain support they would otherwise not have, and modern systems give up nothing measurable in return.
Do I need a separate -race build?
No, not anymore. Earlier releases split the build because -race binaries could not start on Windows 7. That gap is closed, so one build now covers every supported Windows version.
Can I mix this with an official Go install?
Avoid it. Uninstall other Go installs first (or keep isolated GOROOT/PATH) so tools do not pick the wrong binary.
Contributing
Feedback and issue reports are welcome, and we encourage you to open pull requests to contribute to the project. We appreciate your help!
Note that the Go project uses the issue tracker for bug reports and proposals only. See https://go.dev/wiki/Questions for a list of places to ask questions about the Go language.