diff --git a/Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md b/Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md
index f8c0b1f6..ce64293d 100644
--- a/Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md
+++ b/Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md
@@ -469,7 +469,7 @@ swiftly init [--no-modify-profile] [--overwrite] [--platform=<platform>] [--skip
 Update the version of swiftly itself.
 
 ```
-swiftly self-update [--assume-yes] [--verbose] [--version] [--help]
+swiftly self-update [--assume-yes] [--verbose]  [--version] [--help]
 ```
 
 **--assume-yes:**
diff --git a/Sources/Swiftly/SelfUpdate.swift b/Sources/Swiftly/SelfUpdate.swift
index afe9b3ca..2a9b45bc 100644
--- a/Sources/Swiftly/SelfUpdate.swift
+++ b/Sources/Swiftly/SelfUpdate.swift
@@ -5,6 +5,12 @@ import SwiftlyWebsiteAPI
 @preconcurrency import TSCBasic
 import TSCUtility
 
+extension SwiftlyVersion: ExpressibleByArgument {
+    public init?(argument: String) {
+        try? self.init(parsing: argument)
+    }
+}
+
 struct SelfUpdate: SwiftlyCommand {
     public static let configuration = CommandConfiguration(
         abstract: "Update the version of swiftly itself."
@@ -12,8 +18,10 @@ struct SelfUpdate: SwiftlyCommand {
 
     @OptionGroup var root: GlobalOptions
 
+    @Option(help: .hidden) var toVersion: SwiftlyVersion
+
     private enum CodingKeys: String, CodingKey {
-        case root
+        case root, toVersion
     }
 
     mutating func run() async throws {
@@ -31,50 +39,82 @@ struct SelfUpdate: SwiftlyCommand {
             )
         }
 
-        let _ = try await Self.execute(ctx, verbose: self.root.verbose)
+        let _ = try await Self.execute(ctx, verbose: self.root.verbose, version: self.toVersion)
     }
 
-    public static func execute(_ ctx: SwiftlyCoreContext, verbose: Bool) async throws
+    public static func execute(_ ctx: SwiftlyCoreContext, verbose: Bool, version swiftlyVersion: SwiftlyVersion?) async throws
         -> SwiftlyVersion
     {
+        var downloadURL: Foundation.URL?
+        var version: SwiftlyVersion? = swiftlyVersion
+
         await ctx.message("Checking for swiftly updates...")
 
-        let swiftlyRelease = try await ctx.httpClient.getCurrentSwiftlyRelease()
+        if let version {
+#if os(macOS)
+            downloadURL = URL(string: "https://download.swift.org/swiftly/darwin/swiftly-\(version).pkg")
+#endif
+
+#if os(Linux)
+#if arch(x86_64)
+            downloadURL = URL(string: "https://download.swift.org/swiftly/linux/swiftly-\(version)-x86_64.tar.gz")
+#elseif arch(arm64)
+            downloadURL = URL(string: "https://download.swift.org/swiftly/linux/swiftly-\(version)-aarch64.tar.gz")
+#else
+            fatalError("Unsupported architecture")
+#endif
+#else
+            fatalError("Unsupported OS")
+#endif
+
+            guard version > SwiftlyCore.version else {
+                await ctx.print("Self-update does not support downgrading to an older version or re-installing the current version. Current version is \(SwiftlyCore.version) and requested version is \(version).")
+                return SwiftlyCore.version
+            }
 
-        guard try swiftlyRelease.swiftlyVersion > SwiftlyCore.version else {
-            await ctx.message("Already up to date.")
-            return SwiftlyCore.version
+            await ctx.print("Self-update requested to swiftly version \(version)")
         }
 
-        var downloadURL: Foundation.URL?
-        for platform in swiftlyRelease.platforms {
-#if os(macOS)
-            guard platform.isDarwin else {
-                continue
+        if downloadURL == nil {
+            await ctx.print("Checking for swiftly updates...")
+
+            let swiftlyRelease = try await ctx.httpClient.getCurrentSwiftlyRelease()
+
+            guard try swiftlyRelease.swiftlyVersion > SwiftlyCore.version else {
+                await ctx.print("Already up to date.")
+                return SwiftlyCore.version
             }
+            for platform in swiftlyRelease.platforms {
+#if os(macOS)
+                guard platform.isDarwin else {
+                    continue
+                }
 #elseif os(Linux)
-            guard platform.isLinux else {
-                continue
-            }
+                guard platform.isLinux else {
+                    continue
+                }
 #endif
 
 #if arch(x86_64)
-            downloadURL = try platform.x86_64URL
+                downloadURL = try platform.x86_64URL
 #elseif arch(arm64)
-            downloadURL = try platform.arm64URL
+                downloadURL = try platform.arm64URL
 #endif
-        }
+            }
 
-        guard let downloadURL else {
-            throw SwiftlyError(
-                message:
-                "The newest release of swiftly is incompatible with your current OS and/or processor architecture."
-            )
-        }
+            guard let downloadURL else {
+                throw SwiftlyError(
+                    message:
+                    "The newest release of swiftly is incompatible with your current OS and/or processor architecture."
+                )
+            }
+
+            version = try swiftlyRelease.swiftlyVersion
 
-        let version = try swiftlyRelease.swiftlyVersion
+            await ctx.print("A new version of swiftly is available: \(version!)")
+        }
 
-        await ctx.message("A new version is available: \(version)")
+        guard let version, let downloadURL else { fatalError() }
 
         let tmpFile = fs.mktemp()
         try await fs.create(file: tmpFile, contents: nil)
diff --git a/Tests/SwiftlyTests/SelfUpdateTests.swift b/Tests/SwiftlyTests/SelfUpdateTests.swift
index 0f5e355d..badbf5a3 100644
--- a/Tests/SwiftlyTests/SelfUpdateTests.swift
+++ b/Tests/SwiftlyTests/SelfUpdateTests.swift
@@ -21,7 +21,7 @@ import Testing
     func runSelfUpdateTest(latestVersion: SwiftlyVersion) async throws {
         try await SwiftlyTests.withTestHome {
             try await SwiftlyTests.withMockedSwiftlyVersion(latestSwiftlyVersion: latestVersion) {
-                let updatedVersion = try await SelfUpdate.execute(SwiftlyTests.ctx, verbose: true)
+                let updatedVersion = try await SelfUpdate.execute(SwiftlyTests.ctx, verbose: true, version: nil)
                 #expect(latestVersion == updatedVersion)
             }
         }