Many developers start learning programming by building simple projects like todo apps, calculators, and basic CRUD applications. These projects are useful at the beginning, as they help you understand how a programming language works and give you the confidence to start building things. But for many developers, progress stops there.
Real world applications aren’t just about showing data on a screen. They solve real problems, work with real users, and handle situations that don’t always go as planned. This is where many developers struggle.
When I review junior developers’ résumés, I notice a common pattern: the projects section is often filled with beginner apps that look very similar. In today’s job market, this is usually not enough. Employers want to see that you can build something useful, something people would actually use.
The goal of this article is to help you move past simple Hello World projects like todo apps, calculators, and basic CRUD applications. By the end, you’ll understand how to approach building real applications that solve real problems and feel closer to what is built in the real world.
You might be wondering why you should listen to me.
Over the last 10 years, I’ve spent a lot of time building, breaking, and rebuilding software. I have experimented, failed many times, and eventually built applications that thousands of people use every day. A few weeks ago, I launched one of my own SaaS products and watched real users use it at scale, with over a thousand active users during peak hours, without the system crashing.
I’m sharing this because I’ve been where you are now.
If you continue reading, you will:
Learn from real experience building applications used by real users
Learn what not to do, based on years of mistakes and lessons
Learn what actually works and what helps you stand out as a junior developer
Clear up common misconceptions that slow people down
This article is not about theory. It’s about building real things.
To drive this point home, we’ll build a real world application that solves a real problem and is used by real people. Along the way, you’ll learn how to come up with real application ideas, how to build them with simple tools, and how to serve them to many users.
If this sounds like something you’re up for, then let’s get started.
Table of Contents
You Probably Think You Don't Know Enough
Before we begin, I want to clear up the most common misconception beginners have.
Many developers believe they don’t know enough to start building real world applications. They think they need to learn more JavaScript, more Python, or another framework before they are ready. Some even think learning React is the final step that will suddenly make everything click.
This belief is very common, but it’s not true.
If you know how to write HTML, CSS, and a simple loop or function in any programming language, you already have most of what it takes to build a real world application. This tutorial is proof of that.
That’s why I am writing this article. Not to tell you to learn more first, but to show you how far you can go with what you already know.
How to Find Real World Application Ideas
One question beginners ask a lot is, “What kind of apps should I build?”
This is rarely talked about, but it matters more than most people think.
A simple rule is this: build things that already exist.
Look at the apps you use every day, especially the simple ones. Tools that do one thing well. If you find yourself using an app often, that app is solving a real problem.
For example, people use background removers to clean up images. They use URL shorteners to share links. They use notes apps to save quick thoughts. None of these ideas are new, but they are real.
You don’t need to invent something original. You need to understand a problem and build a working solution for it.
When you replicate real tools, you naturally learn how real applications are structured. You also end up with projects that make sense on a résumé, because they solve problems people recognize.
That’s exactly what we are going to do in this tutorial.
What Are We Going to Build?
I’ll tell you now, it is not going to be another Hello World application. We’re going to be building a background remover web application.
This is the kind of tool people actually use. Designers use it for images, content creators use it for thumbnails, and developers build similar features into real products. It works with real files, real data, and real results.
If you want to see the final result before we start building, you can try the working app here: https://iamspruce.github.io/background-remover/

We’ll build this app using simple tools on purpose. Plain HTML, CSS, and JavaScript for the frontend, and Python for the backend. No heavy frameworks and no complicated setup.
Before we continue, let me clear up another common misconception.
Many developers believe that for an application to be taken seriously, it must be built with complex frameworks. In my experience building applications for clients around the world over the last 10 years, not a single client has ever asked me what framework I used.
They only cared about one thing: Did it work, and did it solve their problem?
Users won’t care how your app is built. They care that it works. If HTML, CSS, and JavaScript can solve the problem, there’s no reason to wait months just to learn a new framework.
Now that we understand why we’re building this app and what problem it solves, it’s time to start writing code.
Prerequisites
Before we start writing code, let’s quickly talk about what you need.
This tutorial is not for absolute beginners, but it’s also not super advanced. If you’ve built small things before and you want to build something that actually feels real, you’re in the right place.
What You Should Already Know
You should be comfortable with:
Basic HTML: You know what inputs, buttons, images, and divs do.
Basic CSS: You can style a page and make it look presentable.
Basic JavaScript: You know how to listen for a button click and send a request using
fetch.
That’s enough to follow along.
You don’t need React or any other frontend framework.
Backend Knowledge
For the backend, you don’t need to be a Python expert.
You just need to understand that:
Python can run a server
A server can receive requests
A server can send back responses
Everything else will be explained as we go.
Tools You Need
Make sure you have these installed:
Python 3.9 or newer
Git
A code editor like VS Code
A browser
No Docker knowledge or cloud experience required.
GitHub Account (Important)
We’ll deploy the backend directly from GitHub, so you’ll need a GitHub account.
If you’ve never pushed a project to GitHub or hosted one before, I’ve already written a beginner-friendly guide you can follow first.
Read that article, then come back here.
A Quick Mindset Check
This is not a copy-paste tutorial. You will see real errors. Things may break. That’s normal. That’s how real applications are built.
Now that we’re clear on what you need, let’s start writing code.
We’ll begin with the backend. This is an important decision, so let’s explain it properly.
Step 1: Setting Up the Backend
What Is a Backend and Why Do We Need One?
A backend is a program that runs on a server and does the heavy work for an application.
In our case, the heavy work is image processing. Removing a background from an image requires libraries that can’t run inside the browser. Browsers are designed for safety and user interaction, not for this kind of processing.
That’s why we need a backend.
The backend will:
Receive an image from the user
Remove the background
Send the processed image back
The frontend will simply talk to this backend later.
Keeping Things Simple on Purpose
Because this might be your first real project, we’re going to keep the backend as simple as possible.
One programming language (Python)
One backend file
No complex folder structure
No advanced concepts
This is intentional. Real world applications don’t have to start out complex. They typically start small and grow.
Project Structure
Create a new folder called:
background-remover
Inside it, create a folder for the backend:
background-remover/
backend/
Move into the backend folder:
cd background-remover/backend
Now create a virtual environment:
python -m venv env
A virtual environment keeps this project’s dependencies separate from everything else on your computer. This is standard practice and something you’ll see in real projects.
Now activate it:
macOS or Linux:
source env/bin/activate
Windows:
env\Scripts\activate
Now create a folder for your application code:
mkdir api
Your structure should now look like this:
background-remover/
backend/
env/
api/
At this stage, nothing looks impressive yet. That’s normal.
Installing FastAPI
We’ll use FastAPI to build the backend API.
Install it together with Uvicorn, which is the server that runs our app:
pip install fastapi uvicorn
FastAPI allows us to define endpoints clearly and with very little code, which is perfect for us.
Creating the First Backend File
Inside the api folder, create a file called main.py.
Add the following code:
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health():
return {"status": "ok"}
Let’s pause and understand what this does.
We created a FastAPI application
We added a
/healthendpointThis endpoint simply returns a message
Before building real features, developers always confirm that their server actually runs. That is exactly what this endpoint is for.
Running the Server
From inside the backend folder, start the server:
uvicorn api.main:app --reload
Now open a new terminal and run:
curl http://localhost:8000/health
You should see:
{"status":"ok"}
This is an important moment.
You now have:
A running backend server
A real HTTP endpoint
A response coming from your own code
This is how real backend services start.
Why We Did This First
At this point, you might wonder why we didn’t jump straight into background removal.
The reason is simple: if the server doesn’t run, nothing else matters.
By starting with a health endpoint, we removed uncertainty. We know the server works. Everything we add next is built on top of something we already know is working.
Now that the foundation is in place, we can move on to the real feature.
Step 2: Adding Background Removal to the Backend
Before we write any code here, we need to clear up an important misconception.
A Common Misconception About Machine Learning
When people hear “background removal,” they often think machine learning is too advanced for them.
In real world development, this is almost never how it works.
You aren’t expected to build machine learning models yourself. You use libraries created by others and focus on integrating them correctly.
That is exactly what we’re doing here.
Installing the Background Removal Library
Install the required packages:
pip install rembg pillow onnxruntime
rembghandles the background removalpillowhelps us work with images
For our purposes here, you don’t need to understand how these libraries work internally. You only need to know how to use them.
Adding the Background Removal Endpoint
Now update main.py so it looks like this:
from fastapi import FastAPI, UploadFile, File
from rembg import remove
from PIL import Image
import io
app = FastAPI()
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/remove-bg")
async def remove_bg(file: UploadFile = File(...)):
image_bytes = await file.read()
image = Image.open(io.BytesIO(image_bytes))
output = remove(image)
buffer = io.BytesIO()
output.save(buffer, format="PNG")
buffer.seek(0)
return buffer.getvalue()
Let’s explain this carefully.
The endpoint accepts an uploaded image
The image is read into memory
The background is removed
The result is saved as a PNG with transparency
The image is returned to the client
This endpoint is the core of our application.
Testing the Endpoint With curl
Before building the frontend, we’ll test the backend directly.
Run this command:
curl -X POST \
-F "file=@person.jpg" \
http://localhost:8000/remove-bg \
--output result.png
Open result.png. If you see the background removed, then the backend is complete.
At this point, you have built a backend that:
Accepts real user input
Processes real data
Returns a meaningful result
This is a real backend.
Where We Are Now
Let’s pause and summarize:
We set up a backend server
We confirmed that it runs
We added a real feature
We tested it without a frontend
This is exactly how real developers work.
In the next section, we’ll build a simple frontend that talks to this backend and turns it into something users can interact with.
Step 3: Building the Frontend (What the User Actually Sees)
At this point, our backend is working.
It can receive an image, remove the background, and send the result back. But right now, only developers can use it, because it requires terminal commands.
To make this useful to actual (non-technical) people, we need a frontend.
The frontend is simply the part of the application users see and interact with in their browser.
Clearing a Common Misconception About Frontends
Many beginners think building a frontend means learning a framework first.
This is not true.
Frameworks help later, but they aren’t required to build real applications. Under the hood, every frontend still comes down to HTML, CSS, and JavaScript.
That’s why we are using plain HTML, CSS, and JavaScript here. No React, no build tools, no setup. Just the basics.
What Our Frontend Will Do
Our frontend has one job. It will:
Let the user select an image
Send that image to the backend
Receive the processed image
Show it on the screen
Allow the user to download it
That’s all.
If it does these things correctly, it’s a real frontend.
Creating the Frontend
Go back to the root of your project and create three files:
index.html
styles.css
app.js
This simple setup is very common. Each file has a clear responsibility, which makes the code easier to understand.
Writing the HTML Page
Open index.html and add the following:
<!DOCTYPE html>
<html>
<head>
<title>Background Remover</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Background Remover</h1>
<input type="file" id="imageInput" />
<button id="removeBtn">Remove Background</button>
<div class="result">
<img id="resultImage" />
</div>
<a id="downloadLink" download>Download Image</a>
<script src="app.js"></script>
</body>
</html>
Right now, this page won’t do anything interesting. That’s expected.
HTML only describes what should be on the page. The behavior comes from JavaScript, which we’ll add after we add some styling.
Adding Some Basic Styling
Open styles.css and add this:
body {
font-family: sans-serif;
max-width: 600px;
margin: 40px auto;
}
button {
margin-top: 10px;
}
.result {
margin-top: 20px;
}
img {
max-width: 100%;
}
#downloadLink {
display: none;
margin-top: 10px;
}
This is not about making things look fancy.
The goal here is simply to make the page readable and pleasant to use. Many real internal tools look no better than this. (And you can always improve the styling later if you want.)
Connecting the Frontend to the Backend
Now we’ll write the JavaScript that makes everything work.
Open app.js and add the following code:
const imageInput = document.getElementById("imageInput");
const removeBtn = document.getElementById("removeBtn");
const resultImage = document.getElementById("resultImage");
const downloadLink = document.getElementById("downloadLink");
removeBtn.addEventListener("click", async () => {
const file = imageInput.files[0];
if (!file) {
return;
}
const formData = new FormData();
formData.append("file", file);
const response = await fetch("http://localhost:8000/remove-bg", {
method: "POST",
body: formData,
});
const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);
resultImage.src = imageUrl;
downloadLink.href = imageUrl;
downloadLink.style.display = "inline";
});
Let’s slow down and explain what’s happening here:
We read the image selected by the user
We wrap it in
FormDataso it can be sent to the backendWe send it to our
/remove-bgendpointWe receive the processed image back
We display it and prepare it for download
This is the moment where the frontend and backend finally talk to each other.
Running the Frontend With Live Server
Before testing, make sure your backend is still running.
Now, instead of opening index.html directly, use the Live Server extension in VS Code.
If you don’t have it installed, just open VS Code extensions, search for “Live Server”, and then install it. Then right click on index.html and click “Open with Live Server”.
This starts a small local server for the frontend.
Why does this matter?
Many browser features work better when files are served through a server instead of opened directly from the file system. Using Live Server also matches how real frontends are served.
Testing the Full Application Locally
Now choose an image and click the button.
If everything is working:
The image is sent to the backend
The background is removed
The result appears on the page
The download link shows up
Take a moment here. You have just built:
A backend that processes real data
A frontend that talks to it
A complete application running locally
This is already more than a “Hello World” project.

Clearing One More Misconception
Some beginners look at this and think: “This feels too simple to be a real app.”
This is another misconception. Real applications aren’t defined by complexity. They’re defined by usefulness. If your app solves a real problem and people can use it, it’s a real application.
In the next section, we’ll take this exact app and put it on the internet so anyone can use it.
Step 4: Putting the Backend on the Internet
Right now, your backend is running on your computer.
That means:
It works only for you
If you close your laptop, it stops
If someone opens your frontend, it cannot reach your backend
To fix this, we need to run the backend on a computer that is always online.
This process is called deployment.
A Simple Way to Think About Deployment
Deployment does not mean writing new code.
It simply means this: instead of running your backend on your laptop, you run it on another computer that never sleeps.
Everything we do next exists only to make that happen.
Why We Aren’t Using Netlify or Vercel
You might be wondering why we aren’t using Netlify or Vercel. Those platforms are great, but they’re mainly for frontends.
They work best when your app is:
Static HTML, CSS, and JavaScript
A frontend framework like React or Vue
Small serverless functions
Our backend is different. It’s a Python server that:
Stays running
Accepts image uploads
Processes images
Uses heavy native libraries for background removal
This kind of backend needs a real server, not a lightweight serverless function.
That’s why Netlify and Vercel aren’t a good fit here.
Why We’re Using Cloud Run
Instead, we’re using Cloud Run.
Cloud Run lets us run real backend servers on Google’s infrastructure without managing servers ourselves.
We’re using it because:
It supports full Python backends
It deploys directly from GitHub
It handles scaling and servers for us
It works well with heavy workloads
It’s beginner-friendly
Most importantly, it lets you deploy a real backend without learning cloud commands or CI/CD pipelines.
Preparing the Backend for Cloud Run
Before deploying, we need to make sure our backend is ready.
Creating requirements.txt
Inside the backend folder, create a file called requirements.txt.
Add this:
fastapi
uvicorn
rembg
pillow
onnxruntime
This file tells Cloud Run which Python libraries to install.
Creating a GitHub Repository
Cloud Run deploys directly from GitHub, so our code must live there.
From the project root, run:
git init
git add .
git commit -m "Initial background remover project"
git branch -M main
git remote add origin YOUR_REPO_URL
git push -u origin main
This single repository will be used for both backend and frontend.
Deploying the Backend on Cloud Run
Now open your browser and go to Google Cloud Console.
1. Create a New Project
Open Google Cloud Console and click New Project. Give it a name (for example: background-remover) and then click Create.

2. Open Cloud Run
Use the search bar at the top and search for Cloud Run. Then open it.

Cloud Run will automatically enable the required APIs.
You will be asked to set up billing. Google gives you $300 free credit, which is more than enough for this tutorial.
3. Start Creating the Service
Click Create Service and choose Deploy continuously from a repository.

4. Connect Your GitHub Account
Select GitHub as the repository provider and authenticate your GitHub account. Then install Google Cloud Build on your GitHub account. Choose only the repository you want to deploy.

This allows Google Cloud to build and deploy your code automatically.
5. Select the Repository
Then choose the repository you just installed Cloud Build on and select the main branch.

6. Configure the Build
Now comes the important part: building the context directory.
Set this to:
backend
This tells Cloud Run:
“My backend code lives inside the
backendfolder.”
For the entry command, enter:
uvicorn api.main:app --host 0.0.0.0 --port 8080
This is how Cloud Run starts your FastAPI server.

7. Configure Container Resources
Our backend runs a background-removal model, which is heavy.
So we must increase resources.
Change memory from 512 MB → 2 GB
Set CPU to 4

This ensures the model can load and run properly.
8. Deploy
Now click Create.
Cloud Run will:
Build your app
Install dependencies
Create a container
Deploy it to the internet
You’ll see logs showing the build and deployment process.

This can take a few minutes. That’s normal.
Checking That the Backend Is Live
Once deployment finishes, Cloud Run will show you a public URL.
Test it:
curl https://YOUR_CLOUD_RUN_URL/health
If you see:
{"status":"ok"}
Your backend is officially live on the internet.
Pause here for a second.
You just deployed a real backend. Congratulations.
Updating the Frontend to Use the Live Backend
Open app.js.
Replace:
http://localhost:8000/remove-bg
With:
https://YOUR_CLOUD_RUN_URL/remove-bg
Save the file and reload the frontend.
Step 5: Making the Backend and Frontend Work Together
At this point, we have two things:
A backend running on the internet
A frontend running in the browser
Now we want them to talk to each other.
Open your frontend, select an image, and click the button. You’ll notice that it still doesn’t work. This is expected.
What Is Happening Here?
Your frontend is running on one address, while your backend is running on another address.
Browsers are very strict about this. By default, a browser will block requests from one website to another unless the backend explicitly allows it. This is a security feature.
This rule is called CORS.
Clearing a Common Misconception About CORS
When beginners see a CORS error, they often think something is broken.
Nothing is broken. CORS is simply the browser saying: “I need the backend to confirm that this frontend is allowed to talk to it.”
So all we need to do is tell the backend: “It’s okay for requests to come from my frontend.”
Allowing Only Our Frontend (Not Everyone)
Instead of allowing requests from everywhere, we’ll allow requests only from our frontend. This is a good habit to learn early.
Open backend/api/main.py.
Add this import at the top:
from fastapi.middleware.cors import CORSMiddleware
Then, after creating the FastAPI app, add this:
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://127.0.0.1:5500",
"http://localhost:5500"
],
allow_methods=["POST"],
allow_headers=["*"],
)
Why these URLs?
If you’re using the Live Server extension, your frontend is usually served on port 5500. These are the addresses your browser is using locally.
We’re telling the backend: “Only accept requests from this frontend.”
That is exactly what we want.
Redeploying the Backend
Any time you change backend code, you need to redeploy it.
Since our backend is deployed on Cloud Run and set up with automatic deploy, redeploying is simple, all you need to do is push your changes.
From the project root, run:
git add .
git commit -m "Add CORS configuration"
git push
Cloud Run will automatically detect the change and redeploy your backend.
Wait for the deployment to finish. Once it’s done, your backend will now allow requests from your local frontend.
Testing Again
Reload your frontend in the browser.
Select an image and click the button. This time, it should work.
You just handled a real browser security rule that every production app runs into. That alone is a huge learning step.
Step 6: Putting the Frontend on the Internet (GitHub Pages)
Right now, your frontend works only on your computer.
Just like the backend earlier, this means no one else can use it.
Let’s fix that.
Why GitHub Pages?
Our frontend is:
Just HTML, CSS, and JavaScript
No backend code
No build step
This makes it perfect for GitHub Pages. GitHub Pages can host static sites for free, and it’s very beginner friendly.
Preparing the Frontend for Deployment
Make sure all your frontend files are inside the frontend folder:
frontend/
index.html
styles.css
app.js
Open app.js and make sure the backend URL is the Cloud Run URL, not localhost.
fetch("https://YOUR_CLOUD_RUN_URL/remove-bg", {
method: "POST",
body: formData,
});
Save the file.
Pushing the Frontend to GitHub
We already created a GitHub repository earlier, so we’ll reuse it.
From the project root, run:
git add .
git commit -m "Add frontend and prepare for GitHub Pages"
git push
Enabling GitHub Pages
Go to your repository on GitHub.
Open Settings.
Click Pages.
Under Source, select:
Branch: main
Folder: /(root)
Save everything. After a few seconds, GitHub will give you a URL. This URL is now your frontend on the internet.
Updating CORS for the Live Frontend
Now that the frontend is live, go back to backend/api/main.py.
Replace the local origins with your GitHub Pages URL:
allow_origins=[
"https://YOUR_GITHUB_USERNAME.github.io"
]
Commit and push the change:
git add .
git commit -m "Update CORS for GitHub Pages"
git push
Cloud Run will redeploy the backend automatically.
Final Test
Open your GitHub Pages URL.
Upload an image, remove the background, and download the result.
Everything is now live.
Where You Are Now
Let’s be very clear about what you just did.
You:
Built a real backend
Deployed it to the internet
Built a frontend
Deployed it to the internet
Fixed real production issues
Connected everything properly
This is not a demo project. This is a real application.
In the final section, we’ll wrap things up, talk about what you learned, and where you can go next.
Final Thoughts: What You Just Built Matters
At this point, it is worth stopping and looking back at what you have actually done.
You didn’t just follow steps. You didn’t just copy code. You built a real application.
Let’s Be Clear About What You Accomplished
You started with nothing more than basic tools and ideas.
By the end of this tutorial, you:
Built a backend that processes real data
Used a machine learning tool without fear or overthinking
Exposed a backend to the internet
Built a frontend with plain HTML, CSS, and JavaScript
Connected the frontend and backend properly
Deployed both parts so real users can access them
This is exactly how real applications are built, just at a smaller and more manageable scale.
Why This Is No Longer a “Beginner Project”
Many projects are called beginner projects, but they stop at showing things on a screen.
This one does not.
Your app:
Accepts real input
Performs real work
Runs on real servers
Handles real browser rules
Can be shared with anyone
That is the difference between learning syntax and building software.
The Most Important Lesson in This Tutorial
The most important thing you should take away from this is not the project you built.
It is this: You didn’t need to “know more” before you started.
You learned by building. You figured things out as they appeared. You fixed problems when they showed up.
That is how experience is gained. No one has experience before building real applications. No one lacks experience after building many of them.
What You Can Do Next
This project isn’t the end. It’s a starting point.
Here are a few ideas you can explore next, using what you already know:
Improve the user interface
Add loading states and better feedback
Restrict image size or file types
Add simple rate limiting
Build another small tool that solves a real problem
You don’t need to jump to frameworks yet.
If you can build a few more projects like this, frameworks will make a lot more sense when you meet them.
One Last Thought
If this was your first real project, you should be proud of yourself.
You moved past tutorials, built something useful, and put it on the internet. That’s the line many developers never cross.
Now that you have crossed it, the next one will be easier.
So keep building!
Source Code and Live Demo
If you want to explore the full project or build on top of it, you can find everything here.
Live application: https://iamspruce.github.io/background-remover/
GitHub repository: https://github.com/iamspruce/background-remover
If you have questions, reach me on X at @sprucekhalifa. I write practical tech articles like this regularly.