Next.js Shortened URL Automation
Published: Nov 4, 2021
Last updated: Nov 4, 2021
This post will demonstrate how to create a shortened URL for your Next.js website.
It will follow a similar process that I am using for shortened URLs on my personal blog website, although this example will be in JavaScript as opposed to TypeScript (which my blog is written in).
The final code can be found on my GitHub repo "okeeffed/hello-nextjs-url-shortener".
Prerequisites
- Basic familiarity with Create Next App.
create-next-app
installed.- Basic familiarity with Next.js.
Getting started
We will let create-next-app
create the project directory hello-url-shortener
for us:
$ npx create-next-app hello-url-shortener # ... creates Next.js app for us $ cd hello-url-shortener
At this stage, a working Next.js app is ready for us.
Let's create a couple more folders and files to host our script.
# Create a content folder to host markdown files $ mkdir scripts $ touch scripts/urlShortener.js # Create a folder for some pages - we will be verbose since this is more a demonstration $ mkdir -p pages/content $ touch pages/content/pageA.js pages/content/pageB.js
We will need to install the following dependencies:
npm i --save-dev md5 recursive-readdir
We will use md5
to generate hashes and recursive-readdir
to read the contents of the /pages/content
directory.
Note: this example will demonstrate shortening for two verbose URLs, but you should tweak the script to generate the relevant output to your project. If you are using dynamic content (like I am for my blog), then you need to ensure that you are referencing the data for those paths to know what paths you will need to shorten in the script.
Setting up our pages
To keep things simple, add the following to pages/content/pageA.js
to pages/content/pageB.js
and pages/content/pageB.js
respectively:
// pages/content/pageA.js export default function PageA() { return <div>PageA, woo!</div>; } // pages/content/pageB.js export default function PageB() { return <div>PageB, woo!</div>; }
We are going to keep things simple, as the important part is the redirect.
If you run next dev
in the terminal, you should see the following in the browser for PageA
and PageB
at localhost:3000/content/pageA
and localhost:3000/content/pageB
respectively:
Page A on localhost
Page B on localhost
At this stage, we are now ready to create our shortened URL path.
Writing our redirects script
Next.js docs have information on performing redirects in the next.config.js
file.
A redirect looks like the following:
module.exports = { async redirects() { return [ { source: "/about", destination: "/", permanent: true, }, ]; }, };
What we want to do is write a script that will manage the return value of the redirects
function for us.
First, create the next.config.js
file using touch next.config.js
and add the following:
const urlPaths = require("./public/urls.json"); module.exports = { // ... omitted anything else that may be in this file async redirects() { return urlPaths.redirects; }, };
Now that our config file is setup, we can add the following to our scripts/urlShortener.js
file:
const { readFileSync, writeFileSync, existsSync } = require("fs"); const recursive = require("recursive-readdir"); const md5 = require("md5"); const path = require("path"); async function main() { const contentPagePath = path.resolve(__dirname, "../pages/content"); const urlShortenerFilePath = path.resolve(__dirname, "../public/urls.json"); const urlShortenerFileExists = existsSync(urlShortenerFilePath); const files = await recursive(contentPagePath, ["!*.js"]); const currentUrls = urlShortenerFileExists ? JSON.parse(readFileSync(urlShortenerFilePath, "utf-8")) : { redirects: [] }; // Find all current hashes in the public urls JSON file const currentEntries = currentUrls.redirects.map((url) => url.destination); const currentHashes = currentUrls.redirects.map((url) => url.source); for (const file of files) { const filePath = file // Replace the prefix .replace(`${process.cwd()}/pages`, "") // Replace file JavaScript suffix .replace(".js", ""); // Check if we already have a hash for our file if (currentEntries.includes(filePath)) { continue; } // Create a hash for our file let outputHash = `/${md5(file).slice(0, 4)}`; // If our hash collides, rehash while (currentHashes.includes(outputHash)) { outputHash = `/${md5(outputHash).slice(0, 4)}`; } currentUrls.redirects.push({ source: outputHash, destination: filePath, permanent: true, }); } writeFileSync( urlShortenerFilePath, JSON.stringify(currentUrls, null, 2), "utf8" ); } main();
The script above does the following:
- Assigning some sensible variable defaults after resolving where the files sit.
- Using
recursive-readdir
to fetch all the.js
files in thepages/content
directory. - Checks if our
public
folder has a file calledurls.json
and assigns the value tocurrentUrls
. If not, we are assigningcurrentUrls
to a default object with empty redirects. - Iterating through all of those files file (for us,
pageA.js
andpageB.js
) and generating a hash for each if an entry does not already exist. - Each hash is assigned to our
currentUrls.redirects
array as an object to represents what we saw in the Next.js docs. - Writing that file back out to
public/urls.json
.
All that is left to do is run that script. In the terminal, run node scripts/urlShortener.js
and you should see the output in public/urls.json
:
{ "redirects": [ { "source": "/d475", "destination": "/content/pageA", "permanent": true }, { "source": "/42e2", "destination": "/content/pageB", "permanent": true } ] }
Awesome! So the path /d475
should now redirect to /content/pageA
(and so on for the rest).
To have the next.config.js
input take effect, you will need to restart next dev
.
Once, that is done, head to localhost:3000/{source}
and you should see the page redirect to the destination
(where source
is a value from your public/urls.json
directory).
Success!
What next?
The URL shortener script that we wrote will only apply to shortening the path
part of the URL. If you want to have a shorter page like bit.ly
etc, you will need to buy the domain for that.
For my personal links, I purchased the domain dnok.li
(thinking it was short for Dennis O'Keeffe Link). You will need to apply that to your website, like how I did for my blog (which is being hosted on Vercel):
Applying my domain name
Once that is done, then that in combination with the redirects generator we bring the goods (such as the shortened link for this blog post https://dnok.li/b7c2
).
Summary
Today's post demonstrated how to create a URL shortener for your Next.js website programmatically.
This can be incredibly useful for any URLs taking up precious space on your shared content.
Resources and further reading
- Basic familiarity with Create Next App.
- Basic familiarity with Next.js.
- Final code.
Photo credit: pawel_czerwinski
Next.js Shortened URL Automation
Introduction