Build a URL Shortener: Step-by-Step Project
SkillVeris Team
Engineering Team

A URL shortener works by generating a unique short code for each long URL, storing the mapping in a database, and issuing an HTTP redirect when someone visits the short link.
In this guide, you'll learn:
- The core is two endpoints: one to create a short code and one to redirect from that code to the original URL.
- Base62 encoding of an auto-incrementing ID produces compact, collision-free short codes.
- A 301 or 302 redirect is what actually sends visitors from the short link to the destination.
- The project teaches databases, HTTP redirects, hashing or encoding, and API design in one small app.
1Build a URL Shortener: Step-by-Step Project
A URL shortener works by taking a long URL, generating a short unique code for it, saving the code-to-URL mapping in a database, and returning an HTTP redirect to the original URL whenever someone visits the short link. You build it with two endpoints: one to shorten and one to redirect.
This is one of the best beginner backend projects because it is small enough to finish yet touches every core skill: routing, databases, encoding, and HTTP semantics. Services like Bitly and TinyURL are built on exactly this pattern, just at massive scale.
2How a URL Shortener Works
At its heart, a URL shortener is a lookup table with a redirect on top. Understanding the flow before you code makes the implementation straightforward and shows why each piece exists.
- A user submits a long URL to a create endpoint.
- The server generates a unique short code, such as 'aB3xY'.
- It stores the mapping: short code to original URL, in a database.
- It returns the short link, for example short.ly/aB3xY.
- When a visitor opens that link, the server looks up the code and redirects.
🔑The Core Idea
Everything else — analytics, custom aliases, expiry — is a feature on top of one simple mechanism: map a short code to a long URL, then redirect.
3Generating the Short Code
The short code is the heart of the project, and there are two clean approaches. Each has trade-offs in predictability and simplicity, so choosing deliberately matters for how your service behaves.
- Base62 of an ID: encode an auto-incrementing database ID using [a-zA-Z0-9] for short, guaranteed-unique codes.
- Random string: generate random characters and check the database for collisions.
- Base62 gives the shortest codes but makes them sequential and guessable.
- Random codes are unpredictable but require a uniqueness check on insert.
- For a learning project, Base62 of the row ID is the simplest correct choice.
Why Base62
Base62 packs 62 possible characters into each position, so even a small number of characters covers billions of URLs. Encoding the database's own unique ID means you never have to worry about collisions.
4Building the Two Endpoints
The entire service comes down to two routes. The example below uses Python with FastAPI, but the same shape applies to Express, Flask, or any web framework — a POST to create and a GET to redirect.
- @app.post('/shorten') # accept a long URL, return a short code
- def shorten(url: str): code = encode(save(url)); return {'short': code}
- @app.get('/{code}') # look up the code and redirect
- def redirect(code: str): url = lookup(code); return RedirectResponse(url, status_code=302)
- Return 404 if the code does not exist in the database.
The Redirect Status Code
Use a 302 (temporary) redirect if you want to count clicks or change the target later, and a 301 (permanent) if the mapping will never change. A 301 is cached by browsers, which skips your server on repeat visits.
5Storing the Mappings
You need a persistent store so short links survive restarts. A relational database is the natural fit because the data is a simple, structured table, and it scales comfortably for a learning project.
- Use a table with columns: id, short_code, original_url, created_at.
- Index the short_code column for fast lookups on redirect.
- SQLite is perfect for local development — zero setup, one file.
- Move to PostgreSQL when you deploy for concurrent access.
- Add a clicks column later to store basic analytics.
💡Pro Tip
Validate and normalize the submitted URL before storing it — ensure it has a scheme like https:// so your redirect does not send users to a broken relative path.
6Enhancements That Impress
The basic version works, but a few additions turn it into a genuine portfolio piece. Each enhancement teaches a new skill while keeping the project approachable.
- Click analytics: increment a counter and log timestamps on each redirect.
- Custom aliases: let users request short.ly/my-brand instead of a random code.
- Expiry: add an expires_at column and return 410 Gone for stale links.
- Rate limiting: cap how many links an IP can create to prevent abuse.
- A minimal frontend: a form and a copy-to-clipboard button.
7Common Mistakes to Avoid
Beginners tend to hit the same snags on this project. Avoiding them keeps your shortener correct and secure.
- Not validating the input URL, allowing malformed or malicious values.
- Using a random code without checking for collisions before inserting.
- Forgetting to index the short_code column, making redirects slow at scale.
- Returning the wrong redirect status and confusing browser caching.
- Not handling missing codes, so unknown links crash instead of returning 404.
- Open redirects: blindly redirecting can be abused for phishing — validate targets.
⚠️Watch Out
A shortener that redirects to any URL can be weaponized for phishing. Consider allow-listing schemes and scanning for known-malicious domains before storing.
8Key Takeaways
A URL shortener is a compact project that teaches durable backend fundamentals.
- The core is: generate a short code, store the mapping, redirect on lookup.
- Two endpoints do the job — one to shorten, one to redirect.
- Base62 encoding of a database ID gives short, collision-free codes.
- Choose 301 vs 302 based on whether you need analytics or changeability.
- Add analytics, custom aliases, and validation to make it portfolio-worthy.
9Frequently Asked Questions
Q: How does a URL shortener generate short codes? A: The cleanest approach encodes an auto-incrementing database ID in Base62 (using letters and digits), which guarantees uniqueness and short length. Alternatively you can generate random strings and check the database for collisions before saving.
Q: Should I use a 301 or 302 redirect? A: Use a 302 temporary redirect if you want to count clicks or change the destination later, since it is not cached. Use a 301 permanent redirect for mappings that never change and where browser caching is acceptable.
Q: What database should I use? A: A relational database fits naturally because the data is a simple table of code-to-URL mappings. Use SQLite for local development and move to PostgreSQL when deploying for concurrent access. Index the short-code column for fast lookups.
Q: How do I make my shortener secure? A: Validate and normalize input URLs, handle missing codes with a 404, and guard against open-redirect abuse by allow-listing schemes and screening target domains. Rate limiting also prevents automated abuse of the create endpoint.
Get The Print Version
Download a PDF of this article for offline reading.
About the Publisher
SkillVeris Team
Engineering Team
Our engineering team documents real build journeys so you can learn by doing, not just reading.
View all postsRelated Posts
Never miss an update
Get the latest tutorials and guides delivered to your inbox.
No spam. Unsubscribe anytime.