Hot-swapping a Go program

Sometimes, running an always-on program is important and there a lot of moving parts to move around in order to stop and restart a program.

Recently, I’ve been helping UCC Netsoc develop a Discord Bot written in Go to help their committee and their members as well as provide a clean avenue for people to seek help and technical support from their Systems Administrators. Recently, we’ve been doing a lot of development and then manually deploying to the running server with a  supervisor configuration managing everything.

The easiest method for development was to setup a way to “hot-swap” or replace the compiled binary (running process) with a new one after it was rebuilt.

import (


// watchSelf watches for changes in the main binary and hot-swaps itself for the newly
// built binary file
func watchSelf() (chan struct{}, error) {

    // Retrieve file info for the currently running program
    file, err := osext.Executable()
    if err != nil {
        return nil, err

    // Initialize and prepare a new file watcher
    fmt.Printf("watching %q\n", file)
    w, err := fsnotify.NewWatcher()
    if err != nil {
        return nil, err

    done := make(chan struct{})
    go func() {
        for {
            select {
                case e := <-w.Events:
                    // Events mean changes
                    fmt.Printf("watcher received: %+v", e)

                    // Replace the running system call with a new call
                    // to our newly combined binary
                    err := syscall.Exec(file, os.Args, os.Environ())
                    if err != nil {
                        fmt.Errorf("%#v", err)

                case err := <-w.Errors:
                    // Print out errors as they occur
                    fmt.Printf("watcher error: %+v", err)

                case <-done:
                    // If we ever close the watcher, log it 
                    fmt.Printf("watcher shutting down")

    // Add our running file to be watched
    err = w.Add(file)
    if err != nil {
        return nil, err
    return done, nil

Subscribe To My Newsletter

A couple times a year, I publish a newsletter with a post or two I really enjoyed writing as well as a Scott Hanselman-style list of things that made me smile! If that interests you, subscribe below :)

Subscribe Here