diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json
index e56d8677852..0e13002035c 100644
--- a/client/i18n/locales/english/intro.json
+++ b/client/i18n/locales/english/intro.json
@@ -2229,7 +2229,10 @@
"sykw": { "title": "372", "intro": [] },
"zzhp": { "title": "373", "intro": [] },
"nmve": { "title": "374", "intro": [] },
- "agky": { "title": "375", "intro": [] },
+ "lab-url-shortener-microservice": {
+ "title": "Build a URL Shortener Microservice",
+ "intro": ["In this lab, you will build a URL Shortener Microservice"]
+ },
"lab-exercise-tracker": {
"title": "Build an Exercise Tracker",
"intro": ["In this lab, you will build an exercise tracker"]
diff --git a/client/src/pages/learn/front-end-development/lab-url-shortener-microservice/index.md b/client/src/pages/learn/front-end-development/lab-url-shortener-microservice/index.md
new file mode 100644
index 00000000000..aaf7c1c28f7
--- /dev/null
+++ b/client/src/pages/learn/front-end-development/lab-url-shortener-microservice/index.md
@@ -0,0 +1,9 @@
+---
+title: Introduction to the Build a URL Shortener Microservice
+block: lab-url-shortener-microservice
+superBlock: front-end-development
+---
+
+## Introduction to the Build a URL Shortener Microservice
+
+In this lab you will build a URL Shortener Microservice
diff --git a/curriculum/challenges/_meta/lab-url-shortener-microservice/meta.json b/curriculum/challenges/_meta/lab-url-shortener-microservice/meta.json
new file mode 100644
index 00000000000..2b4c897bee7
--- /dev/null
+++ b/curriculum/challenges/_meta/lab-url-shortener-microservice/meta.json
@@ -0,0 +1,10 @@
+{
+ "name": "Build a URL Shortener Microservice",
+ "isUpcomingChange": true,
+ "dashedName": "lab-url-shortener-microservice",
+ "order": 375,
+ "superBlock": "front-end-development",
+ "challengeOrder": [{ "id": "bd7158d8c443edefaeb5bd0e", "title": "Build a URL Shortener Microservice" }],
+ "helpCategory": "Backend Development",
+ "blockType": "lab"
+ }
diff --git a/curriculum/challenges/english/25-front-end-development/lab-url-shortener-microservice/bd7158d8c443edefaeb5bd0e.md b/curriculum/challenges/english/25-front-end-development/lab-url-shortener-microservice/bd7158d8c443edefaeb5bd0e.md
new file mode 100644
index 00000000000..0fbf80a0bfe
--- /dev/null
+++ b/curriculum/challenges/english/25-front-end-development/lab-url-shortener-microservice/bd7158d8c443edefaeb5bd0e.md
@@ -0,0 +1,107 @@
+---
+id: bd7158d8c443edefaeb5bd0e
+title: URL Shortener Microservice
+challengeType: 4
+dashedName: url-shortener-microservice
+---
+
+# --description--
+
+Build a full stack JavaScript app that is functionally similar to this: https://url-shortener-microservice.freecodecamp.rocks. Working on this project will involve you writing your code using one of the following methods:
+
+- Clone this GitHub repo and complete your project locally.
+- Use our Gitpod starter project to complete your project.
+- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
+
+# --instructions--
+
+**HINT:** Do not forget to use a body parsing middleware to handle the POST requests. Also, you can use the function `dns.lookup(host, cb)` from the `dns` core module to verify a submitted URL.
+
+# --hints--
+
+You should provide your own project, not the example URL.
+
+```js
+(getUserInput) => {
+ assert(
+ !/.*\/url-shortener-microservice\.freecodecamp\.rocks/.test(
+ getUserInput('url')
+ )
+ );
+};
+```
+
+You can POST a URL to `/api/shorturl` and get a JSON response with `original_url` and `short_url` properties. Here's an example: `{ original_url : 'https://freeCodeCamp.org', short_url : 1}`
+
+```js
+async (getUserInput) => {
+ const url = getUserInput('url');
+ const urlVariable = Date.now();
+ const fullUrl = `${url}/?v=${urlVariable}`
+ const res = await fetch(url + '/api/shorturl', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: `url=${fullUrl}`
+ });
+ if (res.ok) {
+ const { short_url, original_url } = await res.json();
+ assert.isNotNull(short_url);
+ assert.strictEqual(original_url, `${url}/?v=${urlVariable}`);
+ } else {
+ throw new Error(`${res.status} ${res.statusText}`);
+ }
+};
+```
+
+When you visit `/api/shorturl/`, you will be redirected to the original URL.
+
+```js
+async (getUserInput) => {
+ const url = getUserInput('url');
+ const urlVariable = Date.now();
+ const fullUrl = `${url}/?v=${urlVariable}`
+ let shortenedUrlVariable;
+ const postResponse = await fetch(url + '/api/shorturl', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: `url=${fullUrl}`
+ });
+ if (postResponse.ok) {
+ const { short_url } = await postResponse.json();
+ shortenedUrlVariable = short_url;
+ } else {
+ throw new Error(`${postResponse.status} ${postResponse.statusText}`);
+ }
+ const getResponse = await fetch(
+ url + '/api/shorturl/' + shortenedUrlVariable
+ );
+ if (getResponse) {
+ const { redirected, url } = getResponse;
+ assert.isTrue(redirected);
+ assert.strictEqual(url,fullUrl);
+ } else {
+ throw new Error(`${getResponse.status} ${getResponse.statusText}`);
+ }
+};
+```
+
+If you pass an invalid URL that doesn't follow the valid `http://www.example.com` format, the JSON response will contain `{ error: 'invalid url' }`
+
+```js
+async (getUserInput) => {
+ const url = getUserInput('url');
+ const res = await fetch(url + '/api/shorturl', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: `url=ftp:/john-doe.invalidTLD`
+ });
+ if (res.ok) {
+ const { error } = await res.json();
+ assert.isNotNull(error);
+ assert.strictEqual(error.toLowerCase(), 'invalid url');
+ } else {
+ throw new Error(`${res.status} ${res.statusText}`);
+ }
+};
+```
+
diff --git a/curriculum/test/utils/mongo-ids.js b/curriculum/test/utils/mongo-ids.js
index 00528e0f62b..572aa4fbfa8 100644
--- a/curriculum/test/utils/mongo-ids.js
+++ b/curriculum/test/utils/mongo-ids.js
@@ -14,6 +14,7 @@ const duplicatedProjectIds = [
'56533eb9ac21ba0edf2244e2',
'aff0395860f5d3034dc0bfc9',
'aa2e6f85cab2ab736c9a9b24',
+ 'bd7158d8c443edefaeb5bd0e',
'5a8b073d06fa14fcfde687aa'
];