diff --git a/internal/lefthook/run/runner.go b/internal/lefthook/run/runner.go
index 37e42c1f..6a8024ee 100644
--- a/internal/lefthook/run/runner.go
+++ b/internal/lefthook/run/runner.go
@@ -11,9 +11,11 @@ import (
 	"regexp"
 	"slices"
 	"sort"
+	"strconv"
 	"strings"
 	"sync"
 	"sync/atomic"
+	"unicode"
 
 	"github.com/charmbracelet/lipgloss"
 	"github.com/spf13/afero"
@@ -330,7 +332,7 @@ func (r *Runner) runCommands(ctx context.Context) {
 		}
 	}
 
-	sort.Strings(commands)
+	sortAlnum(commands)
 
 	interactiveCommands := make([]string, 0)
 	var wg sync.WaitGroup
@@ -529,3 +531,45 @@ func (r *Runner) logExecute(name string, err error, out io.Reader) {
 		log.Infof("%s", err)
 	}
 }
+
+// sortAlnum sorts the command names by preceding numbers if they occur.
+// If the command names starts with letter the command name will be sorted alphabetically.
+//
+//	[]string{"1_command", "10command", "3 command", "command5"} // -> 1_command, 3 command, 10command, command5
+func sortAlnum(strs []string) {
+	sort.SliceStable(strs, func(i, j int) bool {
+		numEnds := -1
+		for idx, ch := range strs[i] {
+			if unicode.IsDigit(ch) {
+				numEnds = idx
+			} else {
+				break
+			}
+		}
+		if numEnds == -1 {
+			return strs[i] < strs[j]
+		}
+		numI, err := strconv.Atoi(strs[i][:numEnds+1])
+		if err != nil {
+			return strs[i] < strs[j]
+		}
+
+		numEnds = -1
+		for idx, ch := range strs[j] {
+			if unicode.IsDigit(ch) {
+				numEnds = idx
+			} else {
+				break
+			}
+		}
+		if numEnds == -1 {
+			return true
+		}
+		numJ, err := strconv.Atoi(strs[j][:numEnds+1])
+		if err != nil {
+			return true
+		}
+
+		return numI < numJ
+	})
+}