After completing my Personal Expense Tracker, I started my fourth project: a URL Shortener. This was also my first web backend project, so the goal was to move from CLI applications into building a small web application and get more practical experience with FastAPI, SQLite, HTML, CSS, and Jinja2.
The result is a simple URL Shortener that takes a long URL, generates a short code, stores the mapping in SQLite, and redirects users to the original URL.
What Is a URL Shortener?
A URL shortener converts a long URL into a shorter link.
For example:
https://example.com/some/very/long/path/to/a/page
can become something like:
http://localhost:8000/aB72xK
When someone opens the shortened URL, the application looks up the short code in the database and redirects them to the original URL.
So the basic flow is:
Long URL
↓
Generate short code
↓
Store both in SQLite
↓
Return short URL
↓
User opens short URL
↓
Look up short code
↓
Redirect to original URL
Project Architecture
I kept the architecture intentionally simple for V1.
There are two main backend responsibilities:
FastAPI application
Handles the web routes, receives the submitted URL, generates the short code, displays the result, and performs the redirect.
SQLite database layer
Handles storing and retrieving the relationship between the short code and the original URL.
The database table contains:
urls
├── short_code
└── original_url
The short_code is the primary key because each shortened URL needs its own unique identifier.
Moving From API-Style Responses to a Web Interface
One of the interesting parts of this project was learning that FastAPI doesn't have to be used only for JSON APIs.
For the first stage of learning FastAPI, I worked with API-style routes and responses.
For this project, I wanted a simple user-facing interface instead.
So I used:
- HTML for the page structure
- CSS for basic styling
- Jinja2 for server-side HTML rendering
- FastAPI as the backend
The user submits a URL through the HTML form, FastAPI processes it, and Jinja2 renders the result back into the page.
I intentionally did not add JavaScript for V1. The goal was to understand the traditional server-rendered web application flow first.
Generating the Short Code
For the current version, the application generates a 6-character short code using letters and numbers.
The generated code is then stored together with the original URL.
For example:
short_code: aB72xK
original_url: https://example.com/some/long/url
When /aB72xK is requested, the application searches for that short code and retrieves the original URL.
Redirecting the User
The redirect is the part that makes the application actually function as a URL shortener.
The application receives a request such as:
/aB72xK
It looks up aB72xK in SQLite.
If the code exists, FastAPI returns a redirect response to the stored original URL.
If the code doesn't exist, the application returns a not-found response.
This helped me understand that a shortened URL isn't just a smaller version of the original URL. It is an identifier that points to data stored by the application.
Keeping V1 Simple
One thing I wanted to maintain throughout this project was a limited scope.
The purpose of V1 was to learn the fundamental workflow, not to build a production-scale URL-shortening service.
Current V1 Scope
- URL shortening
- 6-character short code generation
- SQLite storage
- URL redirection
- Simple HTML + CSS interface
- Jinja2 server-side rendering
- Empty-input handling
That's where I decided to stop V1.
There are many features that could be added later, such as URL expiration, analytics, custom short codes, URL management, authentication, and more.
But adding all of them now would move the project away from its original learning goal.
What I Learned
This project helped me connect several concepts that I had previously learned separately.
I practiced:
- Building a web application with FastAPI
- Connecting FastAPI with SQLite
- Designing a simple database structure
- Using a database class to separate database operations
- Generating unique identifiers
- Handling redirects
- Using Jinja2 templates
- Connecting HTML forms with backend routes
- Serving CSS through FastAPI
- Organizing a small web application
- Deploying the application as a web service
More importantly, I got a better understanding of how the frontend, backend, and database communicate with each other.
Project Structure
url-shortener/
├── main.py
├── database.py
├── requirements.txt
├── templates/
│ └── index.html
├── static/
│ └── style.css
├── .gitignore
├── LICENSE
└── README.md
What's Next?
V1 is now complete.
I want to keep the project available as a small working example of a FastAPI web application rather than continuously adding features without a specific learning goal.
Future versions could explore more advanced concepts when they become relevant to my learning path.
Final Thoughts
This project was a useful step from building command-line applications toward building web applications.
My previous projects helped me practice Python, OOP, CRUD operations, SQLite, and application structure. With the URL Shortener, I was able to bring those concepts together with FastAPI and a browser-based interface.
It's a small application, but it gave me practical experience with the complete basic flow:
Browser → FastAPI → SQLite → FastAPI → Browser
And that's exactly what I wanted from Project #4.
Project #4 — URL Shortener: V1 Complete.
Live Demo: https://url-shortener-k5ed.onrender.com/
Source Code: https://github.com/xDK0d3r/url-shortener
Continue Reading
I also wrote about this project on Dev.to, where I shared more about my learning experience, what I learned while building my first web backend project, and how this project fits into my overall development journey.
If you'd like to read that perspective, check it out here:
Read the Dev.to article →