diff --git a/integrations/api_packages_npm_test.go b/integrations/api_packages_npm_test.go
index bd65a2586714c..02e5138503afb 100644
--- a/integrations/api_packages_npm_test.go
+++ b/integrations/api_packages_npm_test.go
@@ -123,10 +123,16 @@ func TestPackageNpm(t *testing.T) {
 		b, _ := base64.StdEncoding.DecodeString(data)
 		assert.Equal(t, b, resp.Body.Bytes())
 
+		req = NewRequest(t, "GET", fmt.Sprintf("%s/-/%s", root, filename))
+		req = addTokenAuthHeader(req, token)
+		resp = MakeRequest(t, req, http.StatusOK)
+
+		assert.Equal(t, b, resp.Body.Bytes())
+
 		pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
 		assert.NoError(t, err)
 		assert.Len(t, pvs, 1)
-		assert.Equal(t, int64(1), pvs[0].DownloadCount)
+		assert.Equal(t, int64(2), pvs[0].DownloadCount)
 	})
 
 	t.Run("PackageMetadata", func(t *testing.T) {
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 0df6012b566b7..35ac3540b69fe 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -199,11 +199,13 @@ func Routes() *web.Route {
 				r.Get("", npm.PackageMetadata)
 				r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage)
 				r.Get("/-/{version}/{filename}", npm.DownloadPackageFile)
+				r.Get("/-/{filename}", npm.DownloadPackageFileByName)
 			})
 			r.Group("/{id}", func() {
 				r.Get("", npm.PackageMetadata)
 				r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage)
 				r.Get("/-/{version}/{filename}", npm.DownloadPackageFile)
+				r.Get("/-/{filename}", npm.DownloadPackageFileByName)
 			})
 			r.Group("/-/package/@{scope}/{id}/dist-tags", func() {
 				r.Get("", npm.ListPackageTags)
diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go
index d127134d44558..57b24e3a8de87 100644
--- a/routers/api/packages/npm/npm.go
+++ b/routers/api/packages/npm/npm.go
@@ -105,6 +105,49 @@ func DownloadPackageFile(ctx *context.Context) {
 	ctx.ServeStream(s, pf.Name)
 }
 
+// DownloadPackageFileByName finds the version and serves the contents of a package
+func DownloadPackageFileByName(ctx *context.Context) {
+	filename := ctx.Params("filename")
+
+	pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
+		OwnerID: ctx.Package.Owner.ID,
+		Type:    packages_model.TypeNpm,
+		Name: packages_model.SearchValue{
+			ExactMatch: true,
+			Value:      packageNameFromParams(ctx),
+		},
+		HasFileWithName: filename,
+		IsInternal:      false,
+	})
+	if err != nil {
+		apiError(ctx, http.StatusInternalServerError, err)
+		return
+	}
+	if len(pvs) != 1 {
+		apiError(ctx, http.StatusNotFound, nil)
+		return
+	}
+
+	s, pf, err := packages_service.GetFileStreamByPackageVersion(
+		ctx,
+		pvs[0],
+		&packages_service.PackageFileInfo{
+			Filename: filename,
+		},
+	)
+	if err != nil {
+		if err == packages_model.ErrPackageFileNotExist {
+			apiError(ctx, http.StatusNotFound, err)
+			return
+		}
+		apiError(ctx, http.StatusInternalServerError, err)
+		return
+	}
+	defer s.Close()
+
+	ctx.ServeStream(s, pf.Name)
+}
+
 // UploadPackage creates a new package
 func UploadPackage(ctx *context.Context) {
 	npmPackage, err := npm_module.ParsePackage(ctx.Req.Body)