diff --git a/generator/generator.py b/generator/generator.py
index 3f581767..41966856 100644
--- a/generator/generator.py
+++ b/generator/generator.py
@@ -71,9 +71,9 @@ def create_firmware_data(binary, module, version):
     }
 
 
-def get_uploader_id(tools, tool_executable):
+def get_uploader_id(tools, tool_name):
     for t in tools:
-        if t["name"] == tool_executable:
+        if t["name"] == tool_name:
             packager = t["packager"]
             name = t["name"]
             version = t["version"]
@@ -118,15 +118,27 @@ def create_upload_data(fqbn, installed_cores):  # noqa: C901
         installed_json_data = json.load(f)
 
     if f"{tool}.cmd" in platform_upload_data:
-        tool_executable = platform_upload_data[f"{tool}.cmd"]
+        tool_executable_generic = platform_upload_data[f"{tool}.cmd"]
+        tool_executable_linux = platform_upload_data.get(f"{tool}.cmd.linux", tool_executable_generic)
+        tool_executable_windows = platform_upload_data.get(f"{tool}.cmd.windows", "")
+        tool_executable_macosx = platform_upload_data.get(f"{tool}.cmd.macosx", "")
+        tool_name = tool_executable_generic
     elif f"{tool}.cmd.path" in platform_upload_data:
-        tool_executable = platform_upload_data[f"{tool}.cmd.path"].split("/")[-1]
+        tool_executable_generic = "/".join(platform_upload_data[f"{tool}.cmd.path"].split("/")[1:])
+        tool_executable_linux = platform_upload_data.get(f"{tool}.cmd.path.linux", tool_executable_generic)
+        tool_executable_windows = platform_upload_data.get(f"{tool}.cmd.path.windows", "")
+        tool_executable_macosx = platform_upload_data.get(f"{tool}.cmd.path.macosx", "")
+        tool_name = tool_executable_generic.split("/")[-1]
 
-    if tool_executable == "rp2040load":
-        tool_executable = "rp2040tools"
+    tool_config_path = ""
+    if f"{tool}.config.path" in platform_upload_data:
+        tool_config_path = "/".join(platform_upload_data[f"{tool}.config.path"].split("/")[1:])
+
+    if tool_name == "rp2040load":
+        tool_name = "rp2040tools"
 
     tools = installed_json_data["packages"][0]["platforms"][0]["toolsDependencies"]
-    upload_data["uploader"] = get_uploader_id(tools, tool_executable)
+    upload_data["uploader"] = get_uploader_id(tools, tool_name)
 
     if "upload.use_1200bps_touch" in board_upload_data:
         upload_data["upload.use_1200bps_touch"] = bool(board_upload_data["upload.use_1200bps_touch"])
@@ -140,6 +152,7 @@ def create_upload_data(fqbn, installed_cores):  # noqa: C901
         .replace("{path}/{cmd}", "{uploader}")
         .replace("{cmd.path}", "{uploader}")
         .replace("{build.path}/{build.project_name}", "{loader.sketch}")
+        .replace("{config.path}", f"{{tool_dir}}/{tool_config_path}")
         .replace('\\"', "")
     )
 
@@ -163,7 +176,22 @@ def create_upload_data(fqbn, installed_cores):  # noqa: C901
     for k, v in {**board_upload_data, **params}.items():
         command = command.replace(f"{{{k}}}", v)
 
-    upload_data["uploader.command"] = command
+    # This is ugly as hell and I don't care
+    upload_data["uploader.command"] = {}
+    if tool_executable_linux:
+        upload_data["uploader.command"]["linux"] = command.replace(
+            "{uploader}", f"{{tool_dir}}/{tool_executable_linux}"
+        )
+
+    if tool_executable_windows:
+        upload_data["uploader.command"]["windows"] = command.replace(
+            "{uploader}", f"{{tool_dir}}\\{tool_executable_windows}"
+        )
+
+    if tool_executable_macosx:
+        upload_data["uploader.command"]["macosx"] = command.replace(
+            "{uploader}", f"{{tool_dir}}/{tool_executable_macosx}"
+        )
 
     return upload_data
 
diff --git a/indexes/download/testdata/module_firmware_index.json b/indexes/download/testdata/module_firmware_index.json
index 89ec7faf..0cced4e7 100644
--- a/indexes/download/testdata/module_firmware_index.json
+++ b/indexes/download/testdata/module_firmware_index.json
@@ -41,7 +41,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:samd:mkrwifi1010",
@@ -148,7 +151,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:samd:nano_33_iot",
@@ -255,7 +261,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:samd:mkrvidor4000",
@@ -357,7 +366,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:megaavr:uno2018",
@@ -448,7 +460,9 @@
     "module": "NINA",
     "name": "Arduino Uno WiFi Rev2",
     "uploader": "arduino:avrdude@6.3.0-arduino17",
-    "uploader.command": "\"{uploader}\" \"-C{config.path}\" -v  -patmega4809 -cxplainedmini_updi -Pusb  -b115200 -e -D \"-Uflash:w:{loader.sketch}.hex:i\" \"-Ufuse2:w:0x01:m\" \"-Ufuse5:w:0xC9:m\" \"-Ufuse8:w:0x02:m\" "
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bin/avrdude\" \"-C{tool_dir}/etc/avrdude.conf\" -v  -patmega4809 -cxplainedmini_updi -Pusb  -b115200 -e -D \"-Uflash:w:{loader.sketch}.hex:i\" \"-Ufuse2:w:0x01:m\" \"-Ufuse5:w:0xC9:m\" \"-Ufuse8:w:0x02:m\" "
+    }
   },
   {
     "fqbn": "arduino:samd:mkrnb1500",
@@ -485,7 +499,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:mbed_nano:nanorp2040connect",
@@ -508,6 +525,8 @@
     "uploader": "arduino:rp2040tools@1.0.2",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -v -D \"{loader.sketch}.elf\""
+    "uploader.command": {
+      "linux": "\"{tool_dir}/rp2040load\" -v -D \"{loader.sketch}.elf\""
+    }
   }
 ]
\ No newline at end of file
diff --git a/indexes/download/testdata/module_firmware_index.json.sig b/indexes/download/testdata/module_firmware_index.json.sig
index 7eff3591..7cd3f151 100644
Binary files a/indexes/download/testdata/module_firmware_index.json.sig and b/indexes/download/testdata/module_firmware_index.json.sig differ
diff --git a/indexes/firmwareindex/firmwareindex.go b/indexes/firmwareindex/firmwareindex.go
index 585b8665..f2c95892 100644
--- a/indexes/firmwareindex/firmwareindex.go
+++ b/indexes/firmwareindex/firmwareindex.go
@@ -22,6 +22,7 @@ package firmwareindex
 import (
 	"encoding/json"
 	"fmt"
+	"runtime"
 
 	"github.com/arduino/arduino-cli/arduino/security"
 	"github.com/arduino/go-paths-helper"
@@ -32,21 +33,27 @@ import (
 
 // Index represents Boards struct as seen from module_firmware_index.json file.
 type Index struct {
-	Boards    []*indexBoard
+	Boards    []*IndexBoard
 	IsTrusted bool
 }
 
 // indexPackage represents a single entry from module_firmware_index.json file.
-type indexBoard struct {
-	Fqbn            string             `json:"fqbn,required"`
-	Firmwares       []*IndexFirmware   `json:"firmware,required"`
-	LoaderSketch    *IndexLoaderSketch `json:"loader_sketch,required"`
-	Module          string             `json:"module,required"`
-	Name            string             `json:"name,required"`
-	Uploader        string             `json:"uploader,required"`
-	UploadTouch     bool               `json:"upload.use_1200bps_touch"`
-	UploadWait      bool               `json:"upload.wait_for_upload_port"`
-	UploaderCommand string             `json:"uploader.command,required"`
+type IndexBoard struct {
+	Fqbn            string                `json:"fqbn,required"`
+	Firmwares       []*IndexFirmware      `json:"firmware,required"`
+	LoaderSketch    *IndexLoaderSketch    `json:"loader_sketch,required"`
+	Module          string                `json:"module,required"`
+	Name            string                `json:"name,required"`
+	Uploader        string                `json:"uploader,required"`
+	UploadTouch     bool                  `json:"upload.use_1200bps_touch"`
+	UploadWait      bool                  `json:"upload.wait_for_upload_port"`
+	UploaderCommand *IndexUploaderCommand `json:"uploader.command,required"`
+}
+
+type IndexUploaderCommand struct {
+	Linux   string `json:"linux,required"`
+	Windows string `json:"windows"`
+	Macosx  string `json:"macosx"`
 }
 
 // IndexFirmware represents a single Firmware version from module_firmware_index.json file.
@@ -172,14 +179,14 @@ func (i *Index) GetLoaderSketchURL(fqbn string) (string, error) {
 	return "", fmt.Errorf("invalid FQBN: %s", fqbn)
 }
 
-// GetUploaderCommand will take the board's fqbn and return the command used for upload
-func (i *Index) GetUploaderCommand(fqbn string) (string, error) {
-	for _, board := range i.Boards {
-		if board.Fqbn == fqbn {
-			return board.UploaderCommand, nil
-		}
+func (b *IndexBoard) GetUploaderCommand() string {
+	if runtime.GOOS == "windows" && b.UploaderCommand.Windows != "" {
+		return b.UploaderCommand.Linux
+	} else if runtime.GOOS == "darwin" && b.UploaderCommand.Macosx != "" {
+		return b.UploaderCommand.Macosx
 	}
-	return "", fmt.Errorf("invalid FQBN: %s", fqbn)
+	// The linux uploader command is considere to be the generic one
+	return b.UploaderCommand.Linux
 }
 
 // GetModule will take the board's fqbn and return the name of the module
diff --git a/indexes/firmwareindex/firmwareindex_test.go b/indexes/firmwareindex/firmwareindex_test.go
index 158a2239..41b49073 100644
--- a/indexes/firmwareindex/firmwareindex_test.go
+++ b/indexes/firmwareindex/firmwareindex_test.go
@@ -91,22 +91,6 @@ func TestGetLoaderSketchURL(t *testing.T) {
 	require.Empty(t, result)
 }
 
-func TestGetUploaderCommand(t *testing.T) {
-	indexFile := paths.New("testdata/module_firmware_index.json")
-	t.Logf("testing with index: %s", indexFile)
-	index, e := LoadIndexNoSign(indexFile)
-	require.NoError(t, e)
-	require.NotEmpty(t, index)
-
-	result, err := index.GetUploaderCommand("arduino:samd:mkr1000")
-	require.NoError(t, err)
-	require.NotEmpty(t, result)
-
-	result, err = index.GetUploaderCommand("arduino:samd:mkr1001")
-	require.Error(t, err)
-	require.Empty(t, result)
-}
-
 func TestGetModule(t *testing.T) {
 	indexFile := paths.New("testdata/module_firmware_index.json")
 	t.Logf("testing with index: %s", indexFile)
diff --git a/indexes/firmwareindex/testdata/module_firmware_index.json b/indexes/firmwareindex/testdata/module_firmware_index.json
index 89ec7faf..0cced4e7 100644
--- a/indexes/firmwareindex/testdata/module_firmware_index.json
+++ b/indexes/firmwareindex/testdata/module_firmware_index.json
@@ -41,7 +41,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:samd:mkrwifi1010",
@@ -148,7 +151,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:samd:nano_33_iot",
@@ -255,7 +261,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:samd:mkrvidor4000",
@@ -357,7 +366,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:megaavr:uno2018",
@@ -448,7 +460,9 @@
     "module": "NINA",
     "name": "Arduino Uno WiFi Rev2",
     "uploader": "arduino:avrdude@6.3.0-arduino17",
-    "uploader.command": "\"{uploader}\" \"-C{config.path}\" -v  -patmega4809 -cxplainedmini_updi -Pusb  -b115200 -e -D \"-Uflash:w:{loader.sketch}.hex:i\" \"-Ufuse2:w:0x01:m\" \"-Ufuse5:w:0xC9:m\" \"-Ufuse8:w:0x02:m\" "
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bin/avrdude\" \"-C{tool_dir}/etc/avrdude.conf\" -v  -patmega4809 -cxplainedmini_updi -Pusb  -b115200 -e -D \"-Uflash:w:{loader.sketch}.hex:i\" \"-Ufuse2:w:0x01:m\" \"-Ufuse5:w:0xC9:m\" \"-Ufuse8:w:0x02:m\" "
+    }
   },
   {
     "fqbn": "arduino:samd:mkrnb1500",
@@ -485,7 +499,10 @@
     "uploader": "arduino:bossac@1.7.0-arduino3",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    "uploader.command": {
+      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
+      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
+    }
   },
   {
     "fqbn": "arduino:mbed_nano:nanorp2040connect",
@@ -508,6 +525,8 @@
     "uploader": "arduino:rp2040tools@1.0.2",
     "upload.use_1200bps_touch": true,
     "upload.wait_for_upload_port": true,
-    "uploader.command": "\"{uploader}\" -v -D \"{loader.sketch}.elf\""
+    "uploader.command": {
+      "linux": "\"{tool_dir}/rp2040load\" -v -D \"{loader.sketch}.elf\""
+    }
   }
 ]
\ No newline at end of file
diff --git a/indexes/firmwareindex/testdata/module_firmware_index.json.sig b/indexes/firmwareindex/testdata/module_firmware_index.json.sig
index 7eff3591..7cd3f151 100644
Binary files a/indexes/firmwareindex/testdata/module_firmware_index.json.sig and b/indexes/firmwareindex/testdata/module_firmware_index.json.sig differ