diff --git a/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs b/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs
index bebf79dd4e..1a6abf222f 100644
--- a/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs
+++ b/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs
@@ -33,6 +33,31 @@ public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_option_aliases_
                 .Be($"Duplicate alias '--dupe' found on command '{command.Name}'.");
     }
 
+    [Fact]
+    public void ThrowIfInvalid_throws_if_there_are_duplicate_case_insensitive_sibling_option_aliases_on_the_root_command()
+    {
+        var option1 = new CliOption<string>("--dupe", false);
+        var option2 = new CliOption<string>("-y");
+        option2.Aliases.Add("--Dupe");
+
+        var command = new CliRootCommand()
+        {
+            option1,
+            option2
+        };
+
+        var config = new CliConfiguration(command);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should()
+                .Throw<CliConfigurationException>()
+                .Which
+                .Message
+                .Should()
+                .Be($"Duplicate alias '--dupe' found on command '{command.Name}'.");
+    }
+
     [Fact]
     public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_option_aliases_on_a_subcommand()
     {
@@ -60,6 +85,33 @@ public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_option_aliases_
                 .Should()
                 .Be("Duplicate alias '--dupe' found on command 'subcommand'.");
     }
+    [Fact]
+    public void ThrowIfInvalid_throws_if_there_are_duplicate_case_insensitive_sibling_option_aliases_on_a_subcommand()
+    {
+        var option1 = new CliOption<string>("--dupe", false);
+        var option2 = new CliOption<string>("--ok");
+        option2.Aliases.Add("--Dupe");
+
+        var command = new CliRootCommand
+        {
+            new CliCommand("subcommand")
+            {
+                option1,
+                option2
+            }
+        };
+
+        var config = new CliConfiguration(command);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should()
+                .Throw<CliConfigurationException>()
+                .Which
+                .Message
+                .Should()
+                .Be("Duplicate alias '--dupe' found on command 'subcommand'.");
+    }
 
     [Fact]
     public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_subcommand_aliases_on_the_root_command()
@@ -85,6 +137,30 @@ public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_subcommand_alia
                 .Should()
                 .Be($"Duplicate alias 'dupe' found on command '{rootCommand.Name}'.");
     }
+    [Fact]
+    public void ThrowIfInvalid_throws_if_there_are_duplicate_case_insensitive_sibling_subcommand_aliases_on_the_root_command()
+    {
+        var command1 = new CliCommand("dupe", caseSensitive: false);
+        var command2 = new CliCommand("not-a-dupe");
+        command2.Aliases.Add("Dupe");
+
+        var rootCommand = new CliRootCommand
+        {
+            command1,
+            command2
+        };
+
+        var config = new CliConfiguration(rootCommand);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should()
+                .Throw<CliConfigurationException>()
+                .Which
+                .Message
+                .Should()
+                .Be($"Duplicate alias 'dupe' found on command '{rootCommand.Name}'.");
+    }
 
     [Fact]
     public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_subcommand_aliases_on_a_subcommand()
@@ -109,6 +185,29 @@ public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_subcommand_alia
                 .Should()
                 .Be("Duplicate alias 'dupe' found on command 'subcommand'.");
     }
+    [Fact]
+    public void ThrowIfInvalid_throws_if_there_are_duplicate_case_insensitive_sibling_subcommand_aliases_on_a_subcommand()
+    {
+        var command = new CliRootCommand
+        {
+            new CliCommand("subcommand")
+            {
+                new CliCommand("dupe", caseSensitive: false),
+                new CliCommand("not-a-dupe") { Aliases = { "Dupe" } }
+            }
+        };
+
+        var config = new CliConfiguration(command);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should()
+                .Throw<CliConfigurationException>()
+                .Which
+                .Message
+                .Should()
+                .Be("Duplicate alias 'dupe' found on command 'subcommand'.");
+    }
 
     [Fact]
     public void ThrowIfInvalid_throws_if_sibling_command_and_option_aliases_collide_on_the_root_command()
@@ -134,6 +233,30 @@ public void ThrowIfInvalid_throws_if_sibling_command_and_option_aliases_collide_
                 .Should()
                 .Be($"Duplicate alias 'dupe' found on command '{rootCommand.Name}'.");
     }
+    [Fact]
+    public void ThrowIfInvalid_throws_if_case_insensitive_sibling_command_and_option_aliases_collide_on_the_root_command()
+    {
+        var option = new CliOption<string>("dupe", caseSensitive: false);
+        var command = new CliCommand("not-a-dupe");
+        command.Aliases.Add("Dupe");
+
+        var rootCommand = new CliRootCommand
+        {
+            option,
+            command
+        };
+
+        var config = new CliConfiguration(rootCommand);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should()
+                .Throw<CliConfigurationException>()
+                .Which
+                .Message
+                .Should()
+                .Be($"Duplicate alias 'dupe' found on command '{rootCommand.Name}'.");
+    }
 
     [Fact]
     public void ThrowIfInvalid_throws_if_sibling_command_and_option_aliases_collide_on_a_subcommand()
@@ -162,6 +285,33 @@ public void ThrowIfInvalid_throws_if_sibling_command_and_option_aliases_collide_
                 .Should()
                 .Be("Duplicate alias 'dupe' found on command 'subcommand'.");
     }
+    [Fact]
+    public void ThrowIfInvalid_throws_if_case_insensitive_sibling_command_and_option_aliases_collide_on_a_subcommand()
+    {
+        var option = new CliOption<string>("dupe", caseSensitive: false);
+        var command = new CliCommand("not-a-dupe");
+        command.Aliases.Add("Dupe");
+
+        var rootCommand = new CliRootCommand
+        {
+            new CliCommand("subcommand")
+            {
+                option,
+                command
+            }
+        };
+
+        var config = new CliConfiguration(rootCommand);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should()
+                .Throw<CliConfigurationException>()
+                .Which
+                .Message
+                .Should()
+                .Be("Duplicate alias 'dupe' found on command 'subcommand'.");
+    }
 
     [Fact]
     public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_global_option_aliases_on_the_root_command()
@@ -185,6 +335,28 @@ public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_global_option_a
                 .Should()
                 .Be($"Duplicate alias '--dupe' found on command '{command.Name}'.");
     }
+    [Fact]
+    public void ThrowIfInvalid_throws_if_there_are_duplicate_case_insensitive_sibling_global_option_aliases_on_the_root_command()
+    {
+        var option1 = new CliOption<string>("--dupe", caseSensitive: false) { Recursive = true };
+        var option2 = new CliOption<string>("-y") { Recursive = true };
+        option2.Aliases.Add("--Dupe");
+
+        var command = new CliRootCommand();
+        command.Options.Add(option1);
+        command.Options.Add(option2);
+
+        var config = new CliConfiguration(command);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should()
+                .Throw<CliConfigurationException>()
+                .Which
+                .Message
+                .Should()
+                .Be($"Duplicate alias '--dupe' found on command '{command.Name}'.");
+    }
 
     [Fact]
     public void ThrowIfInvalid_does_not_throw_if_global_option_alias_is_the_same_as_local_option_alias()
@@ -204,6 +376,24 @@ public void ThrowIfInvalid_does_not_throw_if_global_option_alias_is_the_same_as_
 
         validate.Should().NotThrow();
     }
+    [Fact]
+    public void ThrowIfInvalid_does_not_throw_if_case_insensitive_global_option_alias_is_the_same_as_local_option_alias()
+    {
+        var rootCommand = new CliRootCommand
+        {
+            new CliCommand("subcommand")
+            {
+                new CliOption<string>("--dupe")
+            }
+        };
+        rootCommand.Options.Add(new CliOption<string>("--Dupe", caseSensitive: false) { Recursive = true });
+
+        var config = new CliConfiguration(rootCommand);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should().NotThrow();
+    }
 
     [Fact]
     public void ThrowIfInvalid_does_not_throw_if_global_option_alias_is_the_same_as_subcommand_alias()
@@ -223,6 +413,24 @@ public void ThrowIfInvalid_does_not_throw_if_global_option_alias_is_the_same_as_
 
         validate.Should().NotThrow();
     }
+    [Fact]
+    public void ThrowIfInvalid_does_not_throw_if_case_insensitive_global_option_alias_is_the_same_as_subcommand_alias()
+    {
+        var rootCommand = new CliRootCommand
+        {
+            new CliCommand("subcommand")
+            {
+                new CliCommand("--dupe")
+            }
+        };
+        rootCommand.Options.Add(new CliOption<string>("--Dupe", caseSensitive: false) { Recursive = true });
+
+        var config = new CliConfiguration(rootCommand);
+
+        var validate = () => config.ThrowIfInvalid();
+
+        validate.Should().NotThrow();
+    }
 
     [Fact]
     public void ThrowIfInvalid_throws_if_a_command_is_its_own_parent()
diff --git a/src/System.CommandLine.Tests/CommandTests.cs b/src/System.CommandLine.Tests/CommandTests.cs
index 8e2157932d..e9696771ef 100644
--- a/src/System.CommandLine.Tests/CommandTests.cs
+++ b/src/System.CommandLine.Tests/CommandTests.cs
@@ -10,7 +10,10 @@ namespace System.CommandLine.Tests
 {
     public class CommandTests
     {
+        private const string caseSensitiveInvoke = "outer inner --option argument1";
+        private const string caseInsensitiveInvoke = "Outer Inner --Option argument1";
         private readonly CliCommand _outerCommand;
+        private readonly CliCommand _outerCommandInsensitive;
 
         public CommandTests()
         {
@@ -21,12 +24,31 @@ public CommandTests()
                     new CliOption<string>("--option")
                 }
             };
+            _outerCommandInsensitive = new CliCommand("outer", caseSensitive: false)
+            {
+                new CliCommand("inner", caseSensitive: false)
+                {
+                    new CliOption<string>("--option", caseSensitive: false)
+                }
+            };
         }
 
         [Fact]
         public void Outer_command_is_identified_correctly_by_RootCommand()
         {
-            var result = _outerCommand.Parse("outer inner --option argument1");
+            var result = _outerCommand.Parse(caseSensitiveInvoke);
+
+            result
+                .RootCommandResult
+                .Command
+                .Name
+                .Should()
+                .Be("outer");
+        }
+        [Fact]
+        public void Outer_command_is_identified_correctly_by_RootCommand_while_case_insensitive()
+        {
+            var result = _outerCommandInsensitive.Parse(caseInsensitiveInvoke);
 
             result
                 .RootCommandResult
@@ -39,7 +61,23 @@ public void Outer_command_is_identified_correctly_by_RootCommand()
         [Fact]
         public void Outer_command_is_identified_correctly_by_Parent_property()
         {
-            var result = _outerCommand.Parse("outer inner --option argument1");
+            var result = _outerCommand.Parse(caseSensitiveInvoke);
+
+            result
+                .CommandResult
+                .Parent
+                .Should()
+                .BeOfType<CommandResult>()
+                .Which
+                .Command
+                .Name
+                .Should()
+                .Be("outer");
+        }
+        [Fact]
+        public void Outer_command_is_identified_correctly_by_Parent_property_while_case_insensitive()
+        {
+            var result = _outerCommandInsensitive.Parse(caseInsensitiveInvoke);
 
             result
                 .CommandResult
@@ -56,7 +94,7 @@ public void Outer_command_is_identified_correctly_by_Parent_property()
         [Fact]
         public void Inner_command_is_identified_correctly()
         {
-            var result = _outerCommand.Parse("outer inner --option argument1");
+            var result = _outerCommand.Parse(caseSensitiveInvoke);
 
             result.CommandResult
                   .Should()
@@ -67,11 +105,73 @@ public void Inner_command_is_identified_correctly()
                   .Should()
                   .Be("inner");
         }
+        [Fact]
+        public void Inner_command_is_identified_correctly_while_case_insensitive()
+        {
+            var result = _outerCommandInsensitive.Parse(caseInsensitiveInvoke);
+
+            result.CommandResult
+                  .Should()
+                  .BeOfType<CommandResult>()
+                  .Which
+                  .Command
+                  .Name
+                  .Should()
+                  .Be("inner");
+        }
+        [Fact]
+        public void Case_sensitive_inner_child_remains_case_sensitive()
+        {
+            var mixedCommand = new CliCommand("outer", caseSensitive: false)
+            {
+                new CliCommand("inner", caseSensitive: true)
+                {
+                    new CliOption<string>("--option", caseSensitive: false)
+                }
+            };
+            var result = mixedCommand.Parse(caseInsensitiveInvoke);
+            result.Errors.Should().NotBeEmpty();
+        }
+        public void Case_insensitive_inner_child_is_identified_correctly_while_outer_is_case_sensitive()
+        {
+            var mixedCommand = new CliCommand("outer")
+            {
+                new CliCommand("inner", caseSensitive: false)
+                {
+                    new CliOption<string>("--option", caseSensitive: false)
+                }
+            };
+            var result = mixedCommand.Parse("outer Inner --Option argument1");
+            result.CommandResult
+                  .Should()
+                  .BeOfType<CommandResult>()
+                  .Which
+                  .Command
+                  .Name
+                  .Should()
+                  .Be("inner");
+        }
 
         [Fact]
         public void Inner_command_option_is_identified_correctly()
         {
-            var result = _outerCommand.Parse("outer inner --option argument1");
+            var result = _outerCommand.Parse(caseSensitiveInvoke);
+
+            result.CommandResult
+                  .Children
+                  .ElementAt(0)
+                  .Should()
+                  .BeOfType<OptionResult>()
+                  .Which
+                  .Option
+                  .Name
+                  .Should()
+                  .Be("--option");
+        }
+        [Fact]
+        public void Inner_command_option_is_identified_correctly_while_case_insensitive()
+        {
+            var result = _outerCommandInsensitive.Parse(caseInsensitiveInvoke);
 
             result.CommandResult
                   .Children
@@ -88,7 +188,20 @@ public void Inner_command_option_is_identified_correctly()
         [Fact]
         public void Inner_command_option_argument_is_identified_correctly()
         {
-            var result = _outerCommand.Parse("outer inner --option argument1");
+            var result = _outerCommand.Parse(caseSensitiveInvoke);
+
+            result.CommandResult
+                  .Children
+                  .ElementAt(0)
+                  .Tokens
+                  .Select(t => t.Value)
+                  .Should()
+                  .BeEquivalentTo("argument1");
+        }
+        [Fact]
+        public void Inner_command_option_argument_is_identified_correctly_while_case_insensitive()
+        {
+            var result = _outerCommandInsensitive.Parse(caseInsensitiveInvoke);
 
             result.CommandResult
                   .Children
@@ -137,6 +250,15 @@ public void Aliases_is_aware_of_added_alias()
 
             command.Aliases.Should().Contain("added");
         }
+        [Fact]
+        public void Aliases_is_aware_of_added_alias_while_case_insensitive()
+        {
+            var command = new CliCommand("original", caseSensitive: false);
+
+            command.Aliases.Add("Added");
+
+            command.Aliases.Should().Contain("added");
+        }
 
 
         [Theory]
diff --git a/src/System.CommandLine.Tests/OptionTests.cs b/src/System.CommandLine.Tests/OptionTests.cs
index 193448b075..1d1ad600e8 100644
--- a/src/System.CommandLine.Tests/OptionTests.cs
+++ b/src/System.CommandLine.Tests/OptionTests.cs
@@ -90,6 +90,13 @@ public void Option_aliases_are_case_sensitive()
 
             option.Aliases.Contains("O").Should().BeFalse();
         }
+        [Fact]
+        public void Option_aliases_are_case_insensitive_while_option_is_case_insensitive()
+        {
+            var option = new CliOption<string>("name", caseSensitive: false, "o");
+
+            option.Aliases.Contains("O").Should().BeTrue();
+        }
 
         [Fact]
         public void Aliases_contains_prefixed_short_value()
diff --git a/src/System.CommandLine/AliasSet.cs b/src/System.CommandLine/AliasSet.cs
index 6007007843..ca7e94177f 100644
--- a/src/System.CommandLine/AliasSet.cs
+++ b/src/System.CommandLine/AliasSet.cs
@@ -8,16 +8,16 @@ internal sealed class AliasSet : ICollection<string>
     {
         private readonly HashSet<string> _aliases;
 
-        internal AliasSet() => _aliases = new(StringComparer.Ordinal);
+        internal AliasSet(bool caseSensitive) => _aliases = new(caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase);
 
-        internal AliasSet(string[] aliases)
+        internal AliasSet(string[] aliases, bool caseSensitive)
         {
             foreach (string alias in aliases)
             {
                 CliSymbol.ThrowIfEmptyOrWithWhitespaces(alias, nameof(alias));
             }
 
-            _aliases = new(aliases, StringComparer.Ordinal);
+            _aliases = new(aliases, caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase);
         }
 
         public int Count => _aliases.Count;
@@ -29,6 +29,7 @@ public void Add(string item)
 
         internal bool Overlaps(AliasSet other) => _aliases.Overlaps(other._aliases);
 
+
         // a struct based enumerator for avoiding allocations
         public HashSet<string>.Enumerator GetEnumerator() => _aliases.GetEnumerator();
 
diff --git a/src/System.CommandLine/CliArgument.cs b/src/System.CommandLine/CliArgument.cs
index aa453bfd72..b38bab439d 100644
--- a/src/System.CommandLine/CliArgument.cs
+++ b/src/System.CommandLine/CliArgument.cs
@@ -19,7 +19,7 @@ public abstract class CliArgument : CliSymbol
         private List<Func<CompletionContext, IEnumerable<CompletionItem>>>? _completionSources = null;
         private List<Action<ArgumentResult>>? _validators = null;
 
-        private protected CliArgument(string name) : base(name, allowWhitespace: true)
+        private protected CliArgument(string name, bool caseSensitive = true) : base(name, allowWhitespace: true, caseSensitive: caseSensitive)
         {
         }
 
diff --git a/src/System.CommandLine/CliCommand.cs b/src/System.CommandLine/CliCommand.cs
index e101bf3948..ca8aebecef 100644
--- a/src/System.CommandLine/CliCommand.cs
+++ b/src/System.CommandLine/CliCommand.cs
@@ -35,7 +35,8 @@ public class CliCommand : CliSymbol, IEnumerable
         /// </summary>
         /// <param name="name">The name of the command.</param>
         /// <param name="description">The description of the command, shown in help.</param>
-        public CliCommand(string name, string? description = null) : base(name)
+        /// <param name="caseSensitive">Whether the command is case sensitive.</param>
+        public CliCommand(string name, string? description = null, bool caseSensitive = true) : base(name, caseSensitive: caseSensitive)
             => Description = description;
 
         /// <summary>
@@ -89,7 +90,7 @@ public IEnumerable<CliSymbol> Children
         /// Gets the unique set of strings that can be used on the command line to specify the command.
         /// </summary>
         /// <remarks>The collection does not contain the <see cref="CliSymbol.Name"/> of the Command.</remarks>
-        public ICollection<string> Aliases => _aliases ??= new();
+        public ICollection<string> Aliases => _aliases ??= new(CaseSensitive);
 
         /// <summary>
         /// Gets or sets the <see cref="CliAction"/> for the Command. The handler represents the action
@@ -308,6 +309,7 @@ void AddCompletionsFor(CliSymbol identifier, AliasSet? aliases)
         }
 
         internal bool EqualsNameOrAlias(string name)
-            => Name.Equals(name, StringComparison.Ordinal) || (_aliases is not null && _aliases.Contains(name));
+            => Name.Equals(name, CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)
+            || (_aliases is not null && _aliases.Contains(name, CaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase));
     }
 }
diff --git a/src/System.CommandLine/CliConfiguration.cs b/src/System.CommandLine/CliConfiguration.cs
index dc02b4e512..d5a316c320 100644
--- a/src/System.CommandLine/CliConfiguration.cs
+++ b/src/System.CommandLine/CliConfiguration.cs
@@ -176,12 +176,12 @@ static void ThrowIfInvalid(CliCommand command)
                     {
                         CliSymbol symbol2 = GetChild(j, command, out AliasSet? aliases2);
 
-                        if (symbol1.Name.Equals(symbol2.Name, StringComparison.Ordinal)
-                            || (aliases1 is not null && aliases1.Contains(symbol2.Name)))
+                        if (symbol1.Name.Equals(symbol2.Name, symbol1.CaseSensitive && symbol2.CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)
+                            || (aliases1 is not null && aliases1.Contains(symbol2.Name, symbol1.CaseSensitive && symbol2.CaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase)))
                         {
                             throw new CliConfigurationException($"Duplicate alias '{symbol2.Name}' found on command '{command.Name}'.");
                         }
-                        else if (aliases2 is not null && aliases2.Contains(symbol1.Name))
+                        else if (aliases2 is not null && aliases2.Contains(symbol1.Name, symbol1.CaseSensitive && symbol2.CaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase))
                         {
                             throw new CliConfigurationException($"Duplicate alias '{symbol1.Name}' found on command '{command.Name}'.");
                         }
diff --git a/src/System.CommandLine/CliDirective.cs b/src/System.CommandLine/CliDirective.cs
index cb7930f5fe..7ad50a712a 100644
--- a/src/System.CommandLine/CliDirective.cs
+++ b/src/System.CommandLine/CliDirective.cs
@@ -22,8 +22,9 @@ public class CliDirective : CliSymbol
         /// Initializes a new instance of the Directive class.
         /// </summary>
         /// <param name="name">The name of the directive. It can't contain whitespaces.</param>
-        public CliDirective(string name)
-            : base(name)
+        /// <param name="caseSensitive">Whether the directive is case sensitive.</param>
+        public CliDirective(string name, bool caseSensitive = true)
+            : base(name, caseSensitive: caseSensitive)
         {
         }
 
diff --git a/src/System.CommandLine/CliOption.cs b/src/System.CommandLine/CliOption.cs
index fd204a8be4..43b47ac092 100644
--- a/src/System.CommandLine/CliOption.cs
+++ b/src/System.CommandLine/CliOption.cs
@@ -17,11 +17,11 @@ public abstract class CliOption : CliSymbol
         internal AliasSet? _aliases;
         private List<Action<OptionResult>>? _validators;
 
-        private protected CliOption(string name, string[] aliases) : base(name)
+        private protected CliOption(string name, string[] aliases, bool caseSensitive = true) : base(name, caseSensitive: caseSensitive)
         {
             if (aliases is { Length: > 0 }) 
             {
-                _aliases = new(aliases);
+                _aliases = new(aliases, caseSensitive);
             }
         }
 
@@ -102,7 +102,7 @@ internal virtual bool Greedy
         /// Gets the unique set of strings that can be used on the command line to specify the Option.
         /// </summary>
         /// <remarks>The collection does not contain the <see cref="CliSymbol.Name"/> of the Option.</remarks>
-        public ICollection<string> Aliases => _aliases ??= new();
+        public ICollection<string> Aliases => _aliases ??= new(CaseSensitive);
 
         /// <summary>
         /// Gets or sets the <see cref="CliAction"/> for the Option. The handler represents the action
diff --git a/src/System.CommandLine/CliOption{T}.cs b/src/System.CommandLine/CliOption{T}.cs
index 0a9e857578..d8176ae5db 100644
--- a/src/System.CommandLine/CliOption{T}.cs
+++ b/src/System.CommandLine/CliOption{T}.cs
@@ -20,9 +20,19 @@ public CliOption(string name, params string[] aliases)
             : this(name, aliases, new CliArgument<T>(name))
         {
         }
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CliOption"/> class.
+        /// </summary>
+        /// <param name="name">The name of the option. It's used for parsing, displaying Help and creating parse errors.</param>>
+        /// <param name="caseSensitive">Whether the option is case sensitive.</param>
+        /// <param name="aliases">Optional aliases. Used for parsing, suggestions and displayed in Help.</param>
+        public CliOption(string name, bool caseSensitive, params string[] aliases)
+            : this(name, aliases, new CliArgument<T>(name), caseSensitive)
+        {
+        }
 
-        private protected CliOption(string name, string[] aliases, CliArgument<T> argument)
-            : base(name, aliases)
+        private protected CliOption(string name, string[] aliases, CliArgument<T> argument, bool caseSensitive = true)
+            : base(name, aliases, caseSensitive)
         {
             argument.AddParent(this);
             _argument = argument;
diff --git a/src/System.CommandLine/CliRootCommand.cs b/src/System.CommandLine/CliRootCommand.cs
index 7c150b2440..4be35c9106 100644
--- a/src/System.CommandLine/CliRootCommand.cs
+++ b/src/System.CommandLine/CliRootCommand.cs
@@ -25,7 +25,8 @@ public class CliRootCommand : CliCommand
         private static string? _executableVersion;
 
         /// <param name="description">The description of the command, shown in help.</param>
-        public CliRootCommand(string description = "") : base(ExecutableName, description)
+        /// <param name="caseSensitive">Whether the option is case sensitive.</param>
+        public CliRootCommand(string description = "", bool caseSensitive = true) : base(ExecutableName, description, caseSensitive)
         {
             Options.Add(new HelpOption());
             Options.Add(new VersionOption()); 
diff --git a/src/System.CommandLine/CliSymbol.cs b/src/System.CommandLine/CliSymbol.cs
index 35ccd1887e..5487f9d4dd 100644
--- a/src/System.CommandLine/CliSymbol.cs
+++ b/src/System.CommandLine/CliSymbol.cs
@@ -12,9 +12,10 @@ namespace System.CommandLine
     /// </summary>
     public abstract class CliSymbol
     {
-        private protected CliSymbol(string name, bool allowWhitespace = false)
+        private protected CliSymbol(string name, bool allowWhitespace = false, bool caseSensitive = true)
         {
             Name = ThrowIfEmptyOrWithWhitespaces(name, nameof(name), allowWhitespace);
+            CaseSensitive = caseSensitive;
         }
 
         /// <summary>
@@ -54,6 +55,8 @@ internal void AddParent(CliSymbol symbol)
         /// </summary>
         public bool Hidden { get; set; }
 
+        internal bool CaseSensitive { get; set; } = true;
+
         /// <summary>
         /// Gets the parent symbols.
         /// </summary>
diff --git a/src/System.CommandLine/Parsing/StringExtensions.cs b/src/System.CommandLine/Parsing/StringExtensions.cs
index 169070c5f7..e5c76499f7 100644
--- a/src/System.CommandLine/Parsing/StringExtensions.cs
+++ b/src/System.CommandLine/Parsing/StringExtensions.cs
@@ -155,10 +155,28 @@ internal static void Tokenize(
                         switch (token.Type)
                         {
                             case CliTokenType.Option:
+                                if (token?.Symbol?.CaseSensitive ?? false)
+                                {
+                                    // If the option is case sensitive, we need to make sure that the match was sensitive
+                                    if(!arg.Equals(token.Value, StringComparison.Ordinal))
+                                    {
+                                        // it doesn't match, so we need to keep going
+                                        break;
+                                    }
+                                }
                                 tokenList.Add(Option(arg, (CliOption)token.Symbol!));
                                 break;
 
                             case CliTokenType.Command:
+                                if (token?.Symbol?.CaseSensitive ?? false)
+                                {
+                                    // If the option is case sensitive, we need to make sure that the match was sensitive
+                                    if (!arg.Equals(token.Value, StringComparison.Ordinal))
+                                    {
+                                        // it doesn't match, so we need to keep going
+                                        break;
+                                    }
+                                }
                                 CliCommand cmd = (CliCommand)token.Symbol!;
                                 if (cmd != currentCommand)
                                 {
@@ -412,7 +430,7 @@ static IEnumerable<string> SplitLine(string line)
 
         private static Dictionary<string, CliToken> ValidTokens(this CliCommand command)
         {
-            Dictionary<string, CliToken> tokens = new(StringComparer.Ordinal);
+            Dictionary<string, CliToken> tokens = new(command.CaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase);
 
             if (command is CliRootCommand { Directives: IList<CliDirective> directives })
             {