diff --git a/lib/util/url.spec.ts b/lib/util/url.spec.ts
index 6e9665ceb3dfd333ee164240194956ca9c7fe04b..b1a5d249801d88d5c238c348489e945a077a9864 100644
--- a/lib/util/url.spec.ts
+++ b/lib/util/url.spec.ts
@@ -1,4 +1,9 @@
-import { resolveBaseUrl, trimTrailingSlash, validateUrl } from './url';
+import {
+  parseUrl,
+  resolveBaseUrl,
+  trimTrailingSlash,
+  validateUrl,
+} from './url';
 
 describe('util/url', () => {
   test.each([
@@ -45,6 +50,7 @@ describe('util/url', () => {
   ])('%s + %s => %s', (baseUrl, x, result) => {
     expect(resolveBaseUrl(baseUrl, x)).toBe(result);
   });
+
   it('validates URLs', () => {
     expect(validateUrl()).toBe(false);
     expect(validateUrl(null)).toBe(false);
@@ -53,6 +59,17 @@ describe('util/url', () => {
     expect(validateUrl('http://github.com')).toBe(true);
     expect(validateUrl('https://github.com')).toBe(true);
   });
+
+  it('parses URL', () => {
+    expect(parseUrl(null)).toBeNull();
+    expect(parseUrl(undefined)).toBeNull();
+
+    const url = parseUrl('https://github.com/renovatebot/renovate');
+    expect(url.protocol).toBe('https:');
+    expect(url.host).toBe('github.com');
+    expect(url.pathname).toBe('/renovatebot/renovate');
+  });
+
   it('trimTrailingSlash', () => {
     expect(trimTrailingSlash('foo')).toBe('foo');
     expect(trimTrailingSlash('/foo/bar')).toBe('/foo/bar');
diff --git a/lib/util/url.ts b/lib/util/url.ts
index 6e61b1eeee889b9c5531ecb0642991250493e1eb..0c9b975f7e961189deffecb14034ccffe65ae1e8 100644
--- a/lib/util/url.ts
+++ b/lib/util/url.ts
@@ -48,3 +48,11 @@ export function validateUrl(url?: string, httpOnly = true): boolean {
     return false;
   }
 }
+
+export function parseUrl(url: string): URL | null {
+  try {
+    return new URL(url);
+  } catch (err) {
+    return null;
+  }
+}