Компилятор выполняет escape analysis: если указатель на переменную "убегает" (возвращается, сохраняется в глобальную переменную, передаётся в канал и т.д.), переменная размещается в куче. Иначе - на стеке. Разработчик не задаёт явно; можно смотреть через go build -gcflags="-m".