Host Your Own URL Shortener with Flask and SQLite
Why depend on third-party services like Bit.ly when you can build your own URL shortener in under 100 lines of Python? In this tutorial, we’re going to walk through creating a self-hosted URL shortener using Flask and SQLite. You’ll learn how to set up the backend, create short URLs, manage redirections, and persist data using a lightweight database.
1. Project Setup and Dependencies
Start by creating a new project folder and initializing a virtual environment. This keeps dependencies isolated.
mkdir flask-url-shortener
cd flask-url-shortener
python3 -m venv venv
source venv/bin/activate
pip install Flask
Create a file named app.py — it’ll contain all our code. We also need the SQLite database, which Flask can work with natively via sqlite3.
2. Build the Flask App and Database
The core idea is to map a short code (like abc123) to a full URL (like https://example.com) and redirect users accordingly. We’ll use SQLite to store this mapping.
from flask import Flask, request, redirect, render_template_string
import sqlite3
import string, random
app = Flask(__name__)
# Initialize the database
conn = sqlite3.connect('urls.db', check_same_thread=False)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS urls (id INTEGER PRIMARY KEY, shortcode TEXT, fullurl TEXT)''')
conn.commit()
This setup uses a simple table with three columns: an ID, a shortcode, and the original URL.
3. Shortcode Generation Logic
To ensure your URLs are short and collision-free (unique), we’ll use a random alphanumeric string generator. Here’s how we create a code and save the mapping:
def generate_shortcode(length=6):
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
def save_url(shortcode, fullurl):
c.execute("INSERT INTO urls (shortcode, fullurl) VALUES (?, ?)", (shortcode, fullurl))
conn.commit()
In production, you might want to verify that the shortcode doesn’t already exist. For simplicity, this demo assumes the probability of collision is low; you can implement retry logic if desired.
4. Create and Redirect Routes
Now, define two routes: one to shortify a URL, and one to redirect from a shortcode to the full link.
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
fullurl = request.form['url']
code = generate_shortcode()
save_url(code, fullurl)
return render_template_string("""
<p>Short URL created: <a href='/{{code}}'>/{{code}}</a></p>
<a href='/'>Shorten another</a>
""", code=code)
return render_template_string("""
<form method='POST'>
<input name='url' placeholder='Enter URL' required>
<button type='submit'>Shorten</button>
</form>
""")
@app.route('/<code>')
def redirect_to_url(code):
c.execute("SELECT fullurl FROM urls WHERE shortcode = ?", (code,))
result = c.fetchone()
if result:
return redirect(result[0])
return "URL not found", 404
When a user submits a URL, we generate a code, save it, and return a clickable link. Visiting that link redirects them to the original URL using a 302 HTTP status.
5. Enhancements, Tips, and Deployment
Enhancements:
- Ensure uniqueness of shortcodes with a uniqueness constraint or retry loop.
- Add an expiration date field to control link lifespan.
- Create an admin panel or stats dashboard for analytics.
Optimization Tips:
- Use connection pooling or a database ORM like SQLAlchemy for larger projects.
- Caching redirects with something like Redis can improve performance under load.
Deployment:
You can deploy this Flask app on Heroku, Fly.io, or any VPS using WSGI with Gunicorn:
gunicorn app:app
Don’t forget to use environment variables and secrets management in production to secure config and limit code visibility.
Conclusion
In under 100 lines of Python, you’ve built a fully functioning URL shortener. This type of project is excellent for learning Flask fundamentals, working with SQLite, and thinking through basic back-end web infrastructure. It’s also a great base to add features such as user accounts, analytics, or REST API support.
Happy coding!
Useful links:


