Tutorial
The Ultimate Guide to Building Your First Web App From Scratch
A step-by-step guide to creating a functional web app from scratch using Python and Flask, covering backend, frontend, database persistence, and deployment.
June 2026 · 12 min read · 1 views · 0 hearts
Advertisement
The Ultimate Guide to Building Your First Web App From Scratch
You’ve written “Hello, World!” a dozen times. Now it’s time to build something real. A web app that people can actually use, not just run in a terminal. This guide walks you through every step—from choosing your stack to deployment—so you end up with a working app and the confidence to build the next one.
Step 1: Choose Your Stack (And Stick With It)
The biggest mistake beginners make? Spending weeks comparing frameworks instead of building. Pick one of these battle-tested combos:
- Python + Flask: Best for absolute beginners. Minimal boilerplate, huge community.
- Python + Django: More batteries included (admin panel, ORM, auth). Faster for complex apps.
- JavaScript + Node.js + Express: If you want full-stack JS.
For this guide, we’ll use Flask—it’s simple, fast, and teaches you the core concepts.
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'Hello, Web!'
if __name__ == '__main__':
app.run(debug=True)
That’s your entire first web app. Run python app.py and open http://127.0.0.1:5000. You’re now a web developer.
Step 2: Plan Before You Code (Yes, Really)
Spend 15 minutes sketching what your app does. For this guide, we’ll build a “Task Tracker”—users add tasks, mark them complete, and delete them. That’s it.
Draw three things on paper: 1. User flow: Home page → Add task → See list → Mark done 2. Data model: Task (id, title, done, created_at) 3. UI layout: Where does the input box go? Where do completed tasks sit?
This planning saves hours of refactoring later.
Step 3: Build the Backend (Your App’s Brain)
Flask handles requests. You need to store tasks somewhere. Start with a simple Python list (we’ll upgrade later).
Your First Route: Show Tasks
tasks = []
@app.route('/')
def index():
return render_template('index.html', tasks=tasks)
Add a Task (POST Request)
from flask import request, redirect
@app.route('/add', methods=['POST'])
def add_task():
title = request.form.get('title')
if title:
tasks.append({'id': len(tasks)+1, 'title': title, 'done': False})
return redirect('/')
Toggle and Delete Tasks
@app.route('/toggle/<int:task_id>')
def toggle_task(task_id):
for task in tasks:
if task['id'] == task_id:
task['done'] = not task['done']
break
return redirect('/')
@app.route('/delete/<int:task_id>')
def delete_task(task_id):
global tasks
tasks = [t for t in tasks if t['id'] != task_id]
return redirect('/')
That’s three routes. Your backend is done.
Step 4: Build the Frontend (Make It Look Good)
Create a templates/ folder and add index.html. Use basic HTML with a little CSS.
<!DOCTYPE html>
<html>
<head>
<title>Task Tracker</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: auto; padding: 2rem; }
.task { display: flex; gap: 1rem; align-items: center; padding: 0.5rem; }
.done { text-decoration: line-through; color: #999; }
input[type="text"] { padding: 0.5rem; flex: 1; }
button { padding: 0.5rem 1rem; background: #007bff; color: white; border: none; cursor: pointer; }
</style>
</head>
<body>
<h1>Task Tracker</h1>
<form action="/add" method="post">
<input type="text" name="title" placeholder="What needs doing?" required>
<button type="submit">Add</button>
</form>
<div>
{% for task in tasks %}
<div class="task">
<a href="/toggle/{{ task.id }}">{{ '✅' if task.done else '⬜' }}</a>
<span class="{{ 'done' if task.done else '' }}">{{ task.title }}</span>
<a href="/delete/{{ task.id }}" style="color: red;">✕</a>
</div>
{% endfor %}
</div>
</body>
</html>
Refresh your browser. You now have a functional, ugly-but-working web app.
Step 5: Add Persistence (Because Lists Get Deleted)
Your tasks vanish when you restart the server. Fix this with SQLite—it’s built into Python and requires zero setup.
Create a Database
import sqlite3
def init_db():
conn = sqlite3.connect('tasks.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS tasks
(id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
done INTEGER DEFAULT 0)''')
conn.commit()
conn.close()
init_db()
Refactor Your Routes to Use the Database
Replace your list-based code with database queries:
def get_tasks():
conn = sqlite3.connect('tasks.db')
c = conn.cursor()
c.execute('SELECT id, title, done FROM tasks ORDER BY id')
tasks = [{'id': row[0], 'title': row[1], 'done': bool(row[2])} for row in c.fetchall()]
conn.close()
return tasks
def add_task_db(title):
conn = sqlite3.connect('tasks.db')
c = conn.cursor()
c.execute('INSERT INTO tasks (title) VALUES (?)', (title,))
conn.commit()
conn.close()
Update your routes to call these functions. Now your tasks survive server restarts.
Step 6: Deploy So the World Can See
Your app runs locally. To share it, you need a host. The easiest free option: Render.
- Push your code to GitHub.
- Create a
requirements.txtfile withflaskin it. - On Render, click “New Web Service” → connect your repo.
- Set the start command:
python app.py - Wait 60 seconds. You’ll get a URL like
your-app.onrender.com.
Share that link with friends. You’ve deployed a real web app.
What You Learned (And What’s Next)
You now know the skeleton of every web app: - Routes handle requests - Templates render HTML - Databases store data persistently - Deployment makes it live
Next steps to level up: - Add a login system using Flask-Login - Style with Bootstrap for professional looks in 10 minutes - Use an ORM like SQLAlchemy to avoid raw SQL - Add tests with pytest
Building your first web app from scratch isn’t about knowing everything—it’s about starting with something tiny, then iterating. You started with one line of Python. Six steps later, you have a deployed app. Keep building.
Advertisement
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.