diff --git a/docs/tutorial/typer-command.md b/docs/tutorial/typer-command.md
index 803b44d0f5..802237e9c7 100644
--- a/docs/tutorial/typer-command.md
+++ b/docs/tutorial/typer-command.md
@@ -215,6 +215,32 @@ Hello Camila
 
 
 
+### Run a package or module with specified function
+
+You can also specify a function directly using the colon syntax:
+
+
+
+```console
+$ typer my_package.main:my_function run --name Camila
+
+Hello Camila
+```
+
+
+
+or with the file path
+
+
+
+```console
+$ typer main.py:my_function run --name Camila
+
+Hello Camila
+```
+
+
+
 ## Options
 
 You can specify one of the following **CLI options**:
@@ -222,6 +248,8 @@ You can specify one of the following **CLI options**:
 * `--app`: the name of the variable with a `Typer()` object to run as the main app.
 * `--func`: the name of the variable with a function that would be used with `typer.run()`.
 
+Alternatively, you can specify the function directly using the syntax `module:function`.
+
 ### Defaults
 
 When your run a script with the `typer` command it will use the app from the following priority:
diff --git a/tests/test_cli/test_multi_func.py b/tests/test_cli/test_multi_func.py
index 8b4b43a94d..62f6c8b362 100644
--- a/tests/test_cli/test_multi_func.py
+++ b/tests/test_cli/test_multi_func.py
@@ -85,6 +85,26 @@ def test_script_func_not_function():
     assert "Not a function:" in result.stderr
 
 
+def test_script_colon_not_function():
+    result = subprocess.run(
+        [
+            sys.executable,
+            "-m",
+            "coverage",
+            "run",
+            "-m",
+            "typer",
+            "tests/assets/cli/multi_func.py:message",
+            "run",
+            "--name",
+            "Camila",
+        ],
+        capture_output=True,
+        encoding="utf-8",
+    )
+    assert "Not a function:" in result.stderr
+
+
 def test_script_func():
     result = subprocess.run(
         [
@@ -104,3 +124,41 @@ def test_script_func():
     )
     assert "Hello" not in result.stdout
     assert "Stuff" in result.stdout
+
+
+def test_script_module_colon_func():
+    result = subprocess.run(
+        [
+            sys.executable,
+            "-m",
+            "coverage",
+            "run",
+            "-m",
+            "typer",
+            "tests.assets.cli.multi_func:say_stuff",
+            "run",
+        ],
+        capture_output=True,
+        encoding="utf-8",
+    )
+    assert "Hello" not in result.stdout
+    assert "Stuff" in result.stdout
+
+
+def test_script_file_colon_func():
+    result = subprocess.run(
+        [
+            sys.executable,
+            "-m",
+            "coverage",
+            "run",
+            "-m",
+            "typer",
+            "tests/assets/cli/multi_func.py:say_stuff",
+            "run",
+        ],
+        capture_output=True,
+        encoding="utf-8",
+    )
+    assert "Hello" not in result.stdout
+    assert "Stuff" in result.stdout
diff --git a/typer/cli.py b/typer/cli.py
index 3fe3d3ee7f..82166be0cb 100644
--- a/typer/cli.py
+++ b/typer/cli.py
@@ -43,6 +43,10 @@ def __init__(self) -> None:
 def maybe_update_state(ctx: click.Context) -> None:
     path_or_module = ctx.params.get("path_or_module")
     if path_or_module:
+        if ":" in path_or_module:
+            module_part, func_part = path_or_module.rsplit(":", 1)
+            path_or_module = module_part
+            ctx.params.update({"func": func_part})
         file_path = Path(path_or_module)
         if file_path.exists() and file_path.is_file():
             state.file = file_path