diff --git a/commands/board/listall.go b/commands/board/listall.go
index 78f945ea864..afa0d78b540 100644
--- a/commands/board/listall.go
+++ b/commands/board/listall.go
@@ -17,9 +17,11 @@ package board
 
 import (
 	"context"
+	"sort"
 	"strings"
 
 	"github.com/arduino/arduino-cli/arduino"
+	"github.com/arduino/arduino-cli/arduino/cores"
 	"github.com/arduino/arduino-cli/arduino/utils"
 	"github.com/arduino/arduino-cli/commands"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
@@ -36,8 +38,8 @@ func ListAll(ctx context.Context, req *rpc.BoardListAllRequest) (*rpc.BoardListA
 	searchArgs := strings.Join(req.GetSearchArgs(), " ")
 
 	list := &rpc.BoardListAllResponse{Boards: []*rpc.BoardListItem{}}
-	for _, targetPackage := range pme.GetPackages() {
-		for _, platform := range targetPackage.Platforms {
+	for _, targetPackage := range toSortedPackageArray(pme.GetPackages()) {
+		for _, platform := range toSortedPlatformArray(targetPackage.Platforms) {
 			installedPlatformRelease := pme.GetInstalledPlatformRelease(platform)
 			// We only want to list boards for installed platforms
 			if installedPlatformRelease == nil {
@@ -93,3 +95,37 @@ func ListAll(ctx context.Context, req *rpc.BoardListAllRequest) (*rpc.BoardListA
 
 	return list, nil
 }
+
+// TODO use a generic function instead of the two below once go >1.18 is adopted.
+//		Without generics we either have to create multiple functions for different map types
+//		or resort to type assertions on the caller side
+
+// toSortedPackageArray takes a packages map and returns its values as array
+// ordered by the map keys alphabetically
+func toSortedPackageArray(sourceMap cores.Packages) []*cores.Package {
+	keys := []string{}
+	for key := range sourceMap {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	sortedValues := make([]*cores.Package, len(keys))
+	for i, key := range keys {
+		sortedValues[i] = sourceMap[key]
+	}
+	return sortedValues
+}
+
+// toSortedPlatformArray takes a packages map and returns its values as array
+// ordered by the map keys alphabetically
+func toSortedPlatformArray(sourceMap map[string]*cores.Platform) []*cores.Platform {
+	keys := []string{}
+	for key := range sourceMap {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	sortedValues := make([]*cores.Platform, len(keys))
+	for i, key := range keys {
+		sortedValues[i] = sourceMap[key]
+	}
+	return sortedValues
+}
diff --git a/internal/integrationtest/board/board_test.go b/internal/integrationtest/board/board_test.go
index b3ac071ddb4..14fbf9ebfd0 100644
--- a/internal/integrationtest/board/board_test.go
+++ b/internal/integrationtest/board/board_test.go
@@ -33,7 +33,10 @@ func TestCorrectBoardListOrdering(t *testing.T) {
 	env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
 	defer env.CleanUp()
 
-	_, _, err := cli.Run("core", "install", "arduino:avr")
+	// install two cores, boards must be ordered by package name and platform name
+	_, _, err := cli.Run("core", "install", "arduino:sam")
+	require.NoError(t, err)
+	_, _, err = cli.Run("core", "install", "arduino:avr")
 	require.NoError(t, err)
 	jsonOut, _, err := cli.Run("board", "listall", "--format", "json")
 	require.NoError(t, err)
@@ -64,7 +67,9 @@ func TestCorrectBoardListOrdering(t *testing.T) {
 		"arduino:avr:yunmini",
 		"arduino:avr:chiwawa",
 		"arduino:avr:one",
-		"arduino:avr:unowifi"
+		"arduino:avr:unowifi",
+		"arduino:sam:arduino_due_x_dbg",
+		"arduino:sam:arduino_due_x"
 	]`)
 }