After completing my Personal Expense Tracker, I started my fourth project: a URL Shortener.
This was also my first web backend project, so this project was a step beyond the CLI applications I had built previously.
The goal was to learn how a backend application connects a web interface, server-side logic, and a database together.
For this project, I used Python, FastAPI, SQLite, Jinja2, HTML, and CSS.
What Does a URL Shortener Do?
A URL Shortener converts a long URL into a shorter URL.
For example:
https://example.com/some/very/long/path/to/a/page
can become:
http://localhost:8000/aB72xK
When someone opens the shortened URL, the application uses the short code to find the original URL in the database and redirects the user.
The basic flow is:
Long URL
↓
Generate short code
↓
Store short code + original URL
↓
Display short URL
↓
User opens short URL
↓
Find original URL
↓
Redirect
From CLI Applications to a Web Application
My previous projects were mainly command-line applications.
With this project, I wanted to understand what happens when a user interacts with an application through a browser.
The basic architecture became:
Browser
↓
FastAPI
↓
SQLite
↓
FastAPI
↓
Browser
This was one of the most useful parts of the project because I could see how the different pieces fit together instead of learning them individually.
Why FastAPI?
I had already started learning the fundamentals of FastAPI before beginning this project.
I had worked with API routes such as:
- GET
- POST
- PUT/PATCH
- DELETE
- Path parameters
- Query parameters
- Request models
For the URL Shortener, I wanted to take the next step and use FastAPI to build an actual web application.
Instead of returning JSON for everything, I used FastAPI to serve HTML pages and process form submissions.
Using Jinja2 for the Interface
For V1, I intentionally decided not to use JavaScript.
Instead, I used Jinja2 for server-side rendering.
The flow is simple:
HTML Form
↓
FastAPI receives the request
↓
Process the URL
↓
Generate short code
↓
Store in SQLite
↓
Render the template again
↓
Display the shortened URL
This gave me a better understanding of the traditional server-rendered web application approach.
I also learned how FastAPI can serve static CSS files separately from the Jinja2 templates.
Database Design
The database is intentionally simple.
The application uses a single urls table:
urls
├── short_code
└── original_url
The short_code is the primary key.
For example:
short_code: aB72xK
original_url: https://example.com/some/long/url
When the user visits /aB72xK, the application searches for that short code and retrieves the corresponding original URL.
If it exists, the application redirects the user.
If it doesn't exist, the application returns a not-found response.
Generating the Short Code
For V1, I kept the implementation simple.
The application generates a 6-character code using letters and numbers.
The generated code becomes the identifier for the stored URL.
I didn't try to build a complex algorithm for generating short URLs because the main learning goal was understanding the complete backend workflow.
Keeping the V1 Scope Small
One thing I wanted to follow with this project was scope control.
There are many things that could be added to a URL shortener:
- Analytics
- URL expiration
- Custom short codes
- User accounts
- URL management
- Click tracking
- Authentication
But I didn't want V1 to become unnecessarily complicated.
Current V1 Scope
The completed V1 includes:
- URL shortening
- 6-character short code generation
- SQLite storage
- URL redirection
- Simple HTML + CSS interface
- Jinja2 server-side rendering
- Empty-input handling
That's enough for the application to demonstrate the fundamental URL-shortening workflow.
What I Learned
This project connected several concepts I had been learning separately.
I practiced:
- Building a web application with FastAPI
- Connecting FastAPI with SQLite
- Designing a simple database
- Separating database operations into a database class
- Generating identifiers
- Handling redirects
- Using Jinja2 templates
- Processing HTML form submissions
- Serving static CSS
- Structuring a small web application
- Deploying a backend application
The biggest takeaway for me was understanding the relationship between the browser, backend, and database.
Project Structure
url-shortener/
├── main.py
├── database.py
├── requirements.txt
├── templates/
│ └── index.html
├── static/
│ └── style.css
├── .gitignore
├── LICENSE
└── README.md
V1 Complete
With the core workflow working, I consider V1 complete.
I intentionally stopped here instead of continuously adding features.
The project is small, but it represents an important step in my learning path: moving from CLI applications into web backend development.
This was my first web backend project, and it gave me practical experience with how a browser-based application communicates with a backend and database.
Final Thoughts
Project #4 started with a simple question:
How does a shortened URL actually work?
Building it helped me understand the answer from the backend side.
A short URL isn't simply a smaller version of a long URL. It's a short identifier that the application stores and uses to find the original URL.
For me, this project was less about building a feature-rich URL shortener and more about learning the fundamentals of web backend development.
Project #4 — URL Shortener: V1 Complete.
Links
Live Demo: https://url-shortener-k5ed.onrender.com/
Source Code: https://github.com/xDK0d3r/url-shortener
A Different Perspective
I also wrote about this project on CoderLegion, where I focused more on the development process, project architecture, and the decisions I made while building the V1.
If you're interested in a different perspective on the same project, you can read it here:
Top comments (0)