diff --git a/cmd/esmapping-generator/generator/esmapping_generator.go b/cmd/esmapping-generator/generator/esmapping_generator.go
new file mode 100644
index 00000000000..6b3f346fdc8
--- /dev/null
+++ b/cmd/esmapping-generator/generator/esmapping_generator.go
@@ -0,0 +1,26 @@
+// Copyright (c) 2025 The Jaeger Authors.
+// SPDX-License-Identifier: Apache-2.0
+
+package generator
+
+import (
+	"fmt"
+
+	"github.com/jaegertracing/jaeger/cmd/esmapping-generator/app"
+	"github.com/jaegertracing/jaeger/cmd/esmapping-generator/app/renderer"
+	"github.com/jaegertracing/jaeger/pkg/es"
+	"github.com/jaegertracing/jaeger/plugin/storage/es/mappings"
+)
+
+func GenerateMappings(options app.Options) (string, error) {
+	if _, err := mappings.MappingTypeFromString(options.Mapping); err != nil {
+		return "", fmt.Errorf("invalid mapping type '%s': please pass either 'jaeger-service' or 'jaeger-span' as the mapping type %w", options.Mapping, err)
+	}
+
+	parsedMapping, err := renderer.GetMappingAsString(es.TextTemplateBuilder{}, &options)
+	if err != nil {
+		return "", fmt.Errorf("failed to render mapping to string: %w", err)
+	}
+
+	return parsedMapping, nil
+}
diff --git a/cmd/esmapping-generator/generator/esmapping_generator_test.go b/cmd/esmapping-generator/generator/esmapping_generator_test.go
new file mode 100644
index 00000000000..3c3f237c80c
--- /dev/null
+++ b/cmd/esmapping-generator/generator/esmapping_generator_test.go
@@ -0,0 +1,87 @@
+// Copyright (c) 2025 The Jaeger Authors.
+// SPDX-License-Identifier: Apache-2.0
+
+package generator
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/crossdock/crossdock-go/assert"
+	"github.com/crossdock/crossdock-go/require"
+
+	"github.com/jaegertracing/jaeger/cmd/esmapping-generator/app"
+	"github.com/jaegertracing/jaeger/pkg/testutils"
+)
+
+func TestGenerateMappings(t *testing.T) {
+	tests := []struct {
+		name      string
+		options   app.Options
+		expectErr bool
+	}{
+		{
+			name: "valid jaeger-span mapping",
+			options: app.Options{
+				Mapping:       "jaeger-span",
+				EsVersion:     7,
+				Shards:        5,
+				Replicas:      1,
+				IndexPrefix:   "jaeger-index",
+				UseILM:        "false",
+				ILMPolicyName: "jaeger-ilm-policy",
+			},
+			expectErr: false,
+		},
+		{
+			name: "valid jaeger-service mapping",
+			options: app.Options{
+				Mapping:       "jaeger-service",
+				EsVersion:     7,
+				Shards:        5,
+				Replicas:      1,
+				IndexPrefix:   "jaeger-service-index",
+				UseILM:        "true",
+				ILMPolicyName: "service-ilm-policy",
+			},
+			expectErr: false,
+		},
+		{
+			name: "invalid mapping type",
+			options: app.Options{
+				Mapping: "invalid-mapping",
+			},
+			expectErr: true,
+		},
+		{
+			name: "missing mapping flag",
+			options: app.Options{
+				Mapping: "",
+			},
+			expectErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result, err := GenerateMappings(tt.options)
+			if tt.expectErr {
+				require.Error(t, err, "Expected an error")
+			} else {
+				require.NoError(t, err, "Did not expect an error")
+
+				var parsed map[string]interface{}
+				err = json.Unmarshal([]byte(result), &parsed)
+				require.NoError(t, err, "Expected valid JSON output")
+
+				assert.NotEmpty(t, parsed["index_patterns"], "Expected index_patterns to be present")
+				assert.NotEmpty(t, parsed["mappings"], "Expected mappings to be present")
+				assert.NotEmpty(t, parsed["settings"], "Expected settings to be present")
+			}
+		})
+	}
+}
+
+func TestMain(m *testing.M) {
+	testutils.VerifyGoLeaks(m)
+}
diff --git a/cmd/esmapping-generator/main.go b/cmd/esmapping-generator/main.go
index 84005602332..12fdeade8f7 100644
--- a/cmd/esmapping-generator/main.go
+++ b/cmd/esmapping-generator/main.go
@@ -7,41 +7,15 @@ import (
 	"fmt"
 	"os"
 
-	"github.com/spf13/cobra"
-	"go.uber.org/zap"
-
-	"github.com/jaegertracing/jaeger/cmd/esmapping-generator/app"
-	"github.com/jaegertracing/jaeger/cmd/esmapping-generator/app/renderer"
-	"github.com/jaegertracing/jaeger/pkg/es"
+	"github.com/jaegertracing/jaeger/internal/storage/elasticsearch/mapping"
 	"github.com/jaegertracing/jaeger/pkg/version"
-	"github.com/jaegertracing/jaeger/plugin/storage/es/mappings"
 )
 
 func main() {
-	logger, _ := zap.NewDevelopment()
-	options := app.Options{}
-	command := &cobra.Command{
-		Use:   "jaeger-esmapping-generator",
-		Short: "Jaeger esmapping-generator prints rendered mappings as string",
-		Long:  `Jaeger esmapping-generator renders passed templates with provided values and prints rendered output to stdout`,
-		Run: func(_ *cobra.Command, _ /* args */ []string) {
-			if _, err := mappings.MappingTypeFromString(options.Mapping); err != nil {
-				logger.Fatal("please pass either 'jaeger-service' or 'jaeger-span' as argument")
-			}
-
-			parsedMapping, err := renderer.GetMappingAsString(es.TextTemplateBuilder{}, &options)
-			if err != nil {
-				logger.Fatal(err.Error())
-			}
-			print(parsedMapping)
-		},
-	}
-
-	options.AddFlags(command)
-
-	command.AddCommand(version.Command())
+	esmappingsCmd := mapping.Command()
+	esmappingsCmd.AddCommand(version.Command())
 
-	if err := command.Execute(); err != nil {
+	if err := esmappingsCmd.Execute(); err != nil {
 		fmt.Println(err.Error())
 		os.Exit(1)
 	}
diff --git a/cmd/jaeger/main.go b/cmd/jaeger/main.go
index d63268845e7..30a50ebdf54 100644
--- a/cmd/jaeger/main.go
+++ b/cmd/jaeger/main.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/jaegertracing/jaeger/cmd/internal/docs"
 	"github.com/jaegertracing/jaeger/cmd/jaeger/internal"
+	"github.com/jaegertracing/jaeger/internal/storage/elasticsearch/mapping"
 	"github.com/jaegertracing/jaeger/pkg/config"
 	"github.com/jaegertracing/jaeger/pkg/version"
 )
@@ -19,6 +20,7 @@ func main() {
 	command := internal.Command()
 	command.AddCommand(version.Command())
 	command.AddCommand(docs.Command(v))
+	command.AddCommand(mapping.Command())
 	config.AddFlags(
 		v,
 		command,
diff --git a/internal/storage/elasticsearch/mapping/command.go b/internal/storage/elasticsearch/mapping/command.go
new file mode 100644
index 00000000000..c0f8bcd89bb
--- /dev/null
+++ b/internal/storage/elasticsearch/mapping/command.go
@@ -0,0 +1,33 @@
+// Copyright (c) 2025 The Jaeger Authors.
+// SPDX-License-Identifier: Apache-2.0
+
+package mapping
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/spf13/cobra"
+
+	"github.com/jaegertracing/jaeger/cmd/esmapping-generator/app"
+	"github.com/jaegertracing/jaeger/cmd/esmapping-generator/generator"
+)
+
+func Command() *cobra.Command {
+	options := app.Options{}
+	command := &cobra.Command{
+		Use:   "elasticsearch-mappings",
+		Short: "Jaeger esmapping-generator prints rendered mappings as string",
+		Long:  "Jaeger esmapping-generator renders passed templates with provided values and prints rendered output to stdout",
+		Run: func(_ *cobra.Command, _ /* args */ []string) {
+			result, err := generator.GenerateMappings(options)
+			if err != nil {
+				log.Fatalf("Error generating mappings: %v", err)
+			}
+			fmt.Println(result)
+		},
+	}
+	options.AddFlags(command)
+
+	return command
+}
diff --git a/internal/storage/elasticsearch/mapping/command_test.go b/internal/storage/elasticsearch/mapping/command_test.go
new file mode 100644
index 00000000000..ce45fe2cceb
--- /dev/null
+++ b/internal/storage/elasticsearch/mapping/command_test.go
@@ -0,0 +1,51 @@
+// Copyright (c) 2025 The Jaeger Authors.
+// SPDX-License-Identifier: Apache-2.0
+
+package mapping
+
+import (
+	"encoding/json"
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"github.com/jaegertracing/jaeger/pkg/testutils"
+)
+
+func TestCommandExecute(t *testing.T) {
+	cmd := Command()
+
+	// TempFile to capture output
+	tempFile, err := os.CreateTemp("", "command-output-*.txt")
+	require.NoError(t, err)
+	defer os.Remove(tempFile.Name())
+
+	// Redirect stdout to the TempFile
+	oldStdout := os.Stdout
+	os.Stdout = tempFile
+	defer func() { os.Stdout = oldStdout }()
+
+	err = cmd.ParseFlags([]string{
+		"--mapping=jaeger-span",
+		"--es-version=7",
+		"--shards=5",
+		"--replicas=1",
+		"--index-prefix=jaeger-index",
+		"--use-ilm=false",
+		"--ilm-policy-name=jaeger-ilm-policy",
+	})
+	require.NoError(t, err)
+	require.NoError(t, cmd.Execute())
+
+	output, err := os.ReadFile(tempFile.Name())
+	require.NoError(t, err)
+
+	var jsonOutput map[string]any
+	err = json.Unmarshal(output, &jsonOutput)
+	require.NoError(t, err, "Output should be valid JSON")
+}
+
+func TestMain(m *testing.M) {
+	testutils.VerifyGoLeaks(m)
+}