diff --git a/lib/versioning/docker/index.spec.ts b/lib/versioning/docker/index.spec.ts
index a1bbb55d1974ea86f61abe453b17cae4c5b351b8..def3a87ea2fcb058392c63b6c52e81d5d6725231 100644
--- a/lib/versioning/docker/index.spec.ts
+++ b/lib/versioning/docker/index.spec.ts
@@ -115,6 +115,30 @@ describe('docker.', () => {
         );
       });
     });
+
+    it('sorts unstable', () => {
+      const versions = [
+        '3.7.0',
+        '3.7-alpine',
+        '3.7.0b1',
+        '3.7.0b5',
+        '3.8.0b1-alpine',
+        '3.8.0-alpine',
+        '3.8.2',
+        '3.8.0',
+      ];
+
+      expect(versions.sort(docker.sortVersions)).toEqual([
+        '3.7.0b1',
+        '3.7.0b5',
+        '3.7.0',
+        '3.7-alpine',
+        '3.8.0b1-alpine',
+        '3.8.0-alpine',
+        '3.8.0',
+        '3.8.2',
+      ]);
+    });
   });
   describe('getNewValue(', () => {
     it('returns toVersion', () => {
@@ -128,4 +152,65 @@ describe('docker.', () => {
       ).toBe('1.2.3');
     });
   });
+
+  it('isStable(version)', () => {
+    const versions = [
+      '3.7.0',
+      '3.7.0b1',
+      '3.7-alpine',
+      '3.8.0-alpine',
+      '3.8.0b1-alpine',
+      '3.8.2',
+    ];
+
+    expect(versions.filter(docker.isStable)).toEqual([
+      '3.7.0',
+      '3.7-alpine',
+      '3.8.0-alpine',
+      '3.8.2',
+    ]);
+  });
+
+  it('isCompatible(version)', () => {
+    const versions = [
+      '3.7.0',
+      '3.7.0b1',
+      '3.7-alpine',
+      '3.8.0-alpine',
+      '3.8.0b1-alpine',
+      '3.8.2',
+    ];
+
+    expect(versions.filter((v) => docker.isCompatible(v, '3.7.0'))).toEqual([
+      '3.7.0',
+      '3.7.0b1',
+      '3.8.2',
+    ]);
+
+    expect(
+      versions.filter((v) => docker.isCompatible(v, '3.7.0-alpine'))
+    ).toEqual(['3.8.0-alpine', '3.8.0b1-alpine']);
+  });
+
+  it('valueToVersion(version)', () => {
+    const versions = [
+      '3.7.0',
+      '3.7.0b1',
+      '3.7-alpine',
+      '3.8.0-alpine',
+      '3.8.0b1-alpine',
+      '3.8.2',
+      undefined,
+    ];
+
+    expect(versions.map(docker.valueToVersion)).toEqual([
+      '3.7.0',
+      '3.7.0b1',
+      '3.7',
+      '3.8.0',
+      '3.8.0b1',
+      '3.8.2',
+      undefined,
+    ]);
+  });
 });
diff --git a/lib/versioning/docker/index.ts b/lib/versioning/docker/index.ts
index e53899ca1041d7f54698d41f30f07c2c85c19d0d..e2ba6bb3c6808cb12427a6263a2138d2363d71a1 100644
--- a/lib/versioning/docker/index.ts
+++ b/lib/versioning/docker/index.ts
@@ -8,16 +8,20 @@ export const urls = [
 ];
 export const supportsRanges = false;
 
-function parse(version: string): any {
+const versionRe = /^(?<version>\d+(?:\.\d+)*)(?<prerelease>.*)$/;
+
+function parse(version: string): generic.GenericVersion {
   const versionPieces = version.replace(/^v/, '').split('-');
   const prefix = versionPieces.shift();
   const suffix = versionPieces.join('-');
-  const release = prefix.split('.').map(Number);
-  // eslint-disable-next-line @typescript-eslint/unbound-method
-  if (release.some(Number.isNaN)) {
+  const m = versionRe.exec(prefix);
+  if (!m?.groups) {
     return null;
   }
-  return { release, suffix };
+
+  const { version: ver, prerelease } = m.groups;
+  const release = ver.split('.').map(Number);
+  return { release, suffix, prerelease };
 }
 
 function valueToVersion(value: string): string {
@@ -47,6 +51,17 @@ function compare(version1: string, vervion2: string): number {
       return part1 - part2;
     }
   }
+  if (parsed1.prerelease !== parsed2.prerelease) {
+    // unstable is lower
+    if (!parsed1.prerelease && parsed2.prerelease) {
+      return 1;
+    }
+    if (parsed1.prerelease && !parsed2.prerelease) {
+      return -1;
+    }
+    // alphabetic order
+    return parsed1.prerelease.localeCompare(parsed2.prerelease);
+  }
   // equals
   return parsed2.suffix.localeCompare(parsed1.suffix);
 }
diff --git a/lib/versioning/loose/generic.ts b/lib/versioning/loose/generic.ts
index 49b5fc39bf2f5af9ff0f501ec7e1685d14f3e2c3..c616bce2433cec94dd6fa8346ae1a538750e6658 100644
--- a/lib/versioning/loose/generic.ts
+++ b/lib/versioning/loose/generic.ts
@@ -2,6 +2,8 @@ import { VersioningApi, NewValueConfig } from '../common';
 
 export interface GenericVersion {
   release: number[];
+  /** prereleases are treated in the standard semver manner, if present */
+  prerelease?: string;
   suffix?: string;
 }
 export interface VersionParser {
@@ -40,7 +42,8 @@ export const parser = (parse: VersionParser): Partial<VersioningApi> => {
   }
 
   function isStable(version: string): boolean {
-    return !!isValid(version);
+    const parsed = parse(version);
+    return parsed && !parsed.prerelease;
   }
 
   return {
@@ -142,7 +145,8 @@ export abstract class GenericVersioningApi<
   }
 
   isStable(version: string): boolean {
-    return this.isValid(version);
+    const parsed = this._parse(version);
+    return parsed && !parsed.prerelease;
   }
 
   isSingleVersion(version: string): string | boolean {