Resume, Portfolio & GitHub Profile Module 6 – Portfolio projects
Hosting project demos without paying
How to choose a host for a static site, an API or an ML demo on a plan that costs nothing, and keep the demo inside its limits, terms and privacy rules.
What you will learn
- Choose a host that fits a static site, an API demo or an ML demo
- Check a demo against its host's documented limits and terms of use
- Protect a demo's keys, sample data and visitors' privacy
- Use only data and content that you have the right to publish
Before you start
What you’ll learn · Before you start
What you will learn
- Choose a host that fits a static site, an API demo or an ML demo
- Check a demo against its host's documented limits and terms of use
- Protect a demo's keys, sample data and visitors' privacy
- Use only data and content that you have the right to publish
Before you start
On this page
Render spins a web service on its Free instance type down after 15 minutes without traffic, and Netlify pauses every project of a team on its Free plan once the month’s 300 credits are spent. A reader opens your demo when it suits them, so plans like these decide whether that reader meets your project or a wait, a sleep page or an error.
This lesson matches each kind of demo to a host whose plan allows it, then plans for what the reader finds.
The kind of demo decides the host
Start from what the demo needs in order to run. Meera has three demos, each of a different kind:
| Demo | What it needs | Hosts that fit |
|---|---|---|
| Bus-pass renewal reminder, built to a static site: A website made of files, such as HTML, CSS, JavaScript and images, that the host sends as they are, without running any code on the server for each request. | Files only | GitHub Pages, Netlify, Vercel, a static Space |
| Canteen queue tracker, in Flask and SQLite | A server running Python | Render, Vercel’s Python functions |
| Mess waste report, made with pandas | No server: a report or a notebook | GitHub Pages for the report |
Each host has one fact to know first:
- GitHub Pages serves static HTML, CSS and JavaScript from a repository; on GitHub Free the repository must be public.
- Vercel’s Hobby plan runs sites and functions, Flask apps included, for non-commercial personal use only.
- Netlify’s Free plan gives a team 300 credits a month, spent on deploys, bandwidth, requests and compute.
- Render runs your app as a web service on its Free instance type, which has a spin-down: A host stopping a service that has had no traffic for a while. The next request waits while the service starts again. after 15 minutes without traffic.
- Hugging Face Spaces hosts static Spaces for everyone, and a personal account in good standing can host up to two Gradio Spaces on ZeroGPU.
- Streamlit Community Cloud deploys Streamlit apps from GitHub, and an app sleeps after 12 hours without traffic.
A notebook needs no host: GitHub renders it as static HTML, without its interactive JavaScript plots, so the README states the results. Answer three questions about your demo, and the table narrows the six hosts:
Answer the questions above: the table then marks what fits your case and says why the rest does not.
| Host and plan | Runs a server or an app | Runs an ML demo | Awake when a reader arrives | Paid or commercial work |
|---|---|---|---|---|
| GitHub Pages Serves: static files from a repository | Poor static files only: no code runs on the server | Mixed only a model that runs in the reader's browser | Good files are served at once, with nothing to wake | Poor not for an online business, e-commerce or commercial software |
| Vercel, Hobby plan Serves: sites and functions, Python included | Good runs Flask, FastAPI and Django apps as functions | Mixed a function gets at most 2 GB of memory and 300 s | Good no sleep page: a function runs on each request | Poor the Hobby plan is for non-commercial personal use only |
| Netlify, Free plan Serves: sites and functions, on 300 credits a month | Mixed functions run, at 10 credits for each GB-hour of compute | Mixed any compute comes out of the same 300 credits | Mixed every project pauses once the month's credits are spent | Mixed the pricing page does not say; read the terms first |
| Render, Free web service Serves: a server that runs your app | Good a web service that runs your own app | Mixed the model and the app share one instance | Poor spins down after 15 minutes without traffic; waking takes about a minute | Poor Render says not to use Free instances for production |
| Hugging Face Spaces Serves: static Spaces, and Gradio on ZeroGPU | Mixed Gradio and Docker Spaces need a paid plan to create | Good a personal account can host up to 2 Gradio Spaces on ZeroGPU | Mixed on free hardware a Space goes to sleep when unused | Mixed the Spaces pages do not say; read the terms first |
| Streamlit Community Cloud Serves: Streamlit apps from GitHub | Mixed Streamlit apps only, deployed from GitHub | Good up to about 2.7 GB of memory and 2 cores | Poor an app sleeps after 12 hours without traffic | Mixed its pages do not say; read the terms first |
How the answers decide
- “What does your demo need in order to run?” Static files only: rules out Streamlit Community Cloud. Static files need no server, so every host but Streamlit serves them; Streamlit Community Cloud deploys Streamlit apps only.
- “What does your demo need in order to run?” A server: an API or a web app: rules out GitHub Pages and adds a caveat to Hugging Face Spaces, Streamlit Community Cloud and Netlify, Free plan. GitHub Pages serves static files only. A Gradio or Docker Space needs a paid plan, Streamlit runs only Streamlit apps, and Netlify's compute costs credits.
- “What does your demo need in order to run?” An ML model behind a form: adds a caveat to GitHub Pages, Vercel, Hobby plan and Render, Free web service. A model needs memory and time on each call. Spaces exist for ML demos, and Streamlit gives an app about 2.7 GB of memory; the others fit only small models.
- “Must the demo answer at once when a reader opens it?” Yes, with no waiting: rules out Render, Free web service and Streamlit Community Cloud and adds a caveat to Hugging Face Spaces and Netlify, Free plan. A reader who arrives after a quiet spell waits for Render to wake or meets Streamlit's sleep page; a Space sleeps and a paused project shows an error.
- “Is it paid or commercial work, such as a client's site or a site that sells something?” Yes: rules out Vercel, Hobby plan and Render, Free web service and adds a caveat to GitHub Pages, Netlify, Free plan, Hugging Face Spaces and Streamlit Community Cloud. Vercel's Hobby plan is for non-commercial personal use and Render says not to use Free instances for production; GitHub Pages excludes online businesses.
In short: static files fit almost anywhere, a server rules out GitHub Pages, an ML demo points to Spaces or Streamlit, and paid work rules out the Hobby plan and Render’s Free instances.
Checkpoint
Check: Matching a demo to a host
A demo that few people visit is asleep when they come
A portfolio demo gets few visitors, and a host that sleeps an idle service will be asleep for most of them. The program replays eight invented visits to Meera’s demos over one month under each host’s documented sleep rule:
# Replays eight invented visits to Meera's demos over a month and counts how many find the demo asleep, under the
# sleep rule each host documents: Render spins a web service on its Free instance type down after 15 minutes without
# traffic and takes about a minute to wake it; Streamlit Community Cloud puts an app to sleep after 12 hours without
# traffic and shows a wake button; GitHub Pages serves static files and does not sleep. Every host starts the month
# asleep, after a quiet spell. Press Edit, change VISITS or the hosts' rules, and run it again.
VISITS = [ # (day of the month, hour, minute)
(3, 10, 5), (3, 10, 11), (9, 14, 30), (12, 9, 10), (12, 18, 40), (18, 11, 0), (25, 16, 20), (30, 13, 45),
]
HOSTS = [ # (name, minutes without traffic before it sleeps, or None, what a visitor meets)
("GitHub Pages, static files", None, ""),
("Render web service, Free instance", 15, "about a minute of waking"),
("Streamlit Community Cloud app", 12 * 60, "a sleep page with a wake button"),
]
minutes = [(day * 24 + hour) * 60 + minute for day, hour, minute in VISITS]
gaps = sorted(b - a for a, b in zip(minutes, minutes[1:]))
print(f"{len(VISITS)} visits in a month; the closest two are {gaps[0]} minutes apart, "
f"the next closest {gaps[1] // 60} h {gaps[1] % 60} min")
for name, sleeps_after, meets in HOSTS:
if sleeps_after is None:
print(f"{name}: awake for {len(VISITS)} of {len(VISITS)} visits")
continue
asleep = 1 + sum(1 for gap in (b - a for a, b in zip(minutes, minutes[1:])) if gap > sleeps_after)
print(f"{name}: asleep for {asleep} of {len(VISITS)} visits, each one meeting {meets}") Output
8 visits in a month; the closest two are 6 minutes apart, the next closest 9 h 30 min GitHub Pages, static files: awake for 8 of 8 visits Render web service, Free instance: asleep for 7 of 8 visits, each one meeting about a minute of waking Streamlit Community Cloud app: asleep for 6 of 8 visits, each one meeting a sleep page with a wake button
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 wake_check.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Static files never sleep, so GitHub Pages serves all eight visits at once. On Render, seven of the eight find the canteen tracker asleep and wait about a minute; only the visit 6 minutes after another finds it awake. On Streamlit, six of the eight meet the sleep page, because two visits came within 12 hours of the one before.
Plan for the sleep instead of fighting it: a short recording or screenshots in the README show the project working in seconds, and a line beside the link says the demo may take a minute to wake. Two more limits can stop a demo: a cap, such as Netlify’s credits, and terms that restrict what you may host. Plans change, so note the day you read each limit. And use only invented data, or data whose licence lets you publish it. A demo is a page any stranger can open, so no real person’s name, number or record belongs in it.
A demo link as the only evidence
Wrong: a resume entry whose only link is a live demo on a host that sleeps. Right: the repository link first, with a recording in its README, and the live demo second. A reader who meets a wait or an error should still see the project work.
Checkpoint
Check: Planning for sleep, caps, terms and data
Each plan's limits in numbers, worked through for one month Pro: opens with a Pro, Premium or Ultimate pass
A plan’s limits only matter once you know what your demo uses. This part works out one month of Meera’s demos against each host’s documented numbers, finds the points where a demo stops, and reads what each host counts as commercial.
In this part:
- Credits, hours and CPU time for one month of demos
- Sizes, storage and builds that a demo outgrows
- What counts as commercial, host by host
1 runnable example (Python) · about 6 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Keeping a demo alive and safe: data, keys and visitors Pro: opens with a Pro, Premium or Ultimate pass
A demo that a stranger can open must survive the host’s restarts, keep its keys out of the browser and collect nothing it does not need. This part fixes the canteen tracker’s vanishing database, reproduces a key leaking from a static build, and ends with a checklist to run before you share the link.
In this part:
- Sample data that survives every restart
- Keys stay on the server: a leak reproduced and fixed
- A health check to run before you share the link
1 runnable example (Python, fixed/app.js, weak/app.js) · about 5 minutes
Opening this part with your pass…Pro part. It opens with the same pass as the part above.
Practise: choose a host and data for five projects
Five invented projects need a home and a data source. Choose both for each; the sample tests explain every wrong choice from the hosts’ own documentation:
Exercise · Easy · Python
Choose a host and data for five projects
Five invented projects need a home and a data source. In hosts.py, fill in CHOICES: for each project, a host copied exactly from HOSTS and a data source copied exactly from that project's list in DATA.
- Exam timetable viewer: a React app built to static files that shows a department's invented exam timetable.
- Hostel complaint tracker: a Flask API with a SQLite database, where residents log complaints and the warden closes them.
- Leaf disease classifier: a Gradio app around an image model that needs a GPU for each prediction.
- Bakery order page: a site that a local bakery pays you to build, where customers order cakes and pay online.
- Rainfall notebook: a Jupyter notebook that analyses fifty years of rainfall from a public dataset.
Choose as this lesson does: what the demo needs to run decides the host, paid work stays off plans meant for personal projects, and a demo uses only invented data or data whose licence lets you publish it. Every wrong choice gets a message that says why, from the hosts' own documentation.
Starter code · hosts.py
# Choose a host and a data source for each project of the prompt. Copy every value exactly from the lists below.
HOSTS = [
"GitHub Pages",
"Vercel, Hobby plan",
"Render, Free web service",
"Hugging Face Spaces, Gradio on ZeroGPU",
"Streamlit Community Cloud",
"the notebook rendered on GitHub",
"a paid plan in the client's own name",
]
DATA = {
"exam timetable viewer": ["an invented timetable", "the real timetable with students' roll numbers"],
"hostel complaint tracker": ["invented sample complaints", "last term's complaints with residents' names"],
"leaf disease classifier": ["a leaf image dataset under CC BY 4.0, credited", "photos copied from a farmers' forum"],
"bakery order page": ["the bakery's own menu, with its permission", "a rival bakery's photos and prices"],
"rainfall notebook": ["a public rainfall dataset under CC BY 4.0, credited", "a paid dataset shared by a friend"],
}
CHOICES = {
"exam timetable viewer": {"host": "", "data": ""},
"hostel complaint tracker": {"host": "", "data": ""},
"leaf disease classifier": {"host": "", "data": ""},
"bakery order page": {"host": "", "data": ""},
"rainfall notebook": {"host": "", "data": ""},
} The sample tests · test_hosts.py
from hosts import CHOICES, DATA, HOSTS
FITS = {
"exam timetable viewer": {"GitHub Pages", "Vercel, Hobby plan"},
"hostel complaint tracker": {"Render, Free web service", "Vercel, Hobby plan"},
"leaf disease classifier": {"Hugging Face Spaces, Gradio on ZeroGPU"},
"bakery order page": {"a paid plan in the client's own name"},
"rainfall notebook": {"the notebook rendered on GitHub", "GitHub Pages"},
}
WHY = {
"GitHub Pages": "GitHub Pages is a static site hosting service: no code runs on its server, and it is not for an online business or e-commerce",
"Vercel, Hobby plan": "Vercel's Hobby plan gives a function at most 2 GB of memory and 1 vCPU, and it is for non-commercial personal use only",
"Render, Free web service": "a Free web service runs a server app, and Render says not to use Free instances for production",
"Hugging Face Spaces, Gradio on ZeroGPU": "a Gradio Space on ZeroGPU is for an ML demo that runs a model",
"Streamlit Community Cloud": "Streamlit Community Cloud deploys Streamlit apps only, with up to 2 cores and about 2.7 GB of memory and no GPU listed",
"the notebook rendered on GitHub": "GitHub renders a notebook as static HTML, so it cannot run an app",
"a paid plan in the client's own name": "a personal project fits a plan that costs nothing, and a paid plan in a client's name is for paid work",
}
NEEDS = {
"exam timetable viewer": "static files, which any static host serves at once",
"hostel complaint tracker": "a server that runs its Flask API",
"leaf disease classifier": "a GPU for each prediction",
"bakery order page": "a plan whose terms allow paid work",
"rainfall notebook": "no server at all, since GitHub shows a notebook as it is",
}
DATA_OK = {
"exam timetable viewer": "an invented timetable",
"hostel complaint tracker": "invented sample complaints",
"leaf disease classifier": "a leaf image dataset under CC BY 4.0, credited",
"bakery order page": "the bakery's own menu, with its permission",
"rainfall notebook": "a public rainfall dataset under CC BY 4.0, credited",
}
def check(project):
choice = CHOICES[project]
assert choice["host"] in HOSTS, f"{project}: copy a host exactly from HOSTS"
assert choice["host"] in FITS[project], (
f"{project}: not {choice['host']}, because {WHY[choice['host']]}; this project needs {NEEDS[project]}"
)
assert choice["data"] in DATA[project], f"{project}: copy a data source exactly from its list in DATA"
assert choice["data"] == DATA_OK[project], (
f"{project}: {choice['data']} is not yours to publish; use invented data or data whose licence allows it"
)
def test_exam_timetable_viewer():
"""the static timetable viewer: a static host and invented data"""
check("exam timetable viewer")
def test_hostel_complaint_tracker():
"""the Flask API: a host that runs a server, and invented complaints"""
check("hostel complaint tracker")
def test_leaf_disease_classifier():
"""the GPU model: a Gradio Space on ZeroGPU and a licensed, credited dataset"""
check("leaf disease classifier")
def test_bakery_order_page():
"""the paid site: off the plans meant for personal projects, with the bakery's permission"""
check("bakery order page")
def test_rainfall_notebook():
"""the notebook: shown on GitHub, with a licensed, credited dataset"""
check("rainfall notebook") A hint
Ask the lesson's three questions of each project in turn: does it need static files, a server or an ML model; must it answer at once; and is it paid work? The bakery's site is paid work, so none of the plans for personal projects fits.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Then answer questions on choosing a host and planning for sleep, starting with the idea you have answered worst so far:
Practice that adapts to you
Practise this lesson
7 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up (fresher to mid-level): How does hosting a static site differ from hosting an app that needs a server?
A static site is files, such as HTML, CSS, JavaScript and images, that the host sends as they are, so any static host serves them and nothing needs to wake up. An app that needs a server runs code on each request, such as a Flask API reading a database, so the host must keep a process for it. That is why GitHub Pages fits a React front end built to static files but not a Flask app, and why a server host’s idle service may be asleep at the first request.
Three questions of this module’s bank go further:
-
Fresher to mid
During a video interview, the interviewer opens your demo link. It shows a loading screen for a minute, then an error. What do you do in the moment, and what do you change afterwards?
-
Fresher to mid
Your static demo calls a weather service with an API key written into its JavaScript, and a friend points out that anyone can read the key. What do you do, in what order, and how do you stop it happening again?
-
Fresher to mid
A local bakery offers to pay you to build its website, and you plan to host it on the same plan that costs nothing as your portfolio. What do you check before you agree, and what do you tell the bakery?
Flashcards · 8 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
What decides where a portfolio demo can be hosted?
What the demo needs in order to run. Static files fit almost any host; an app that needs a server, such as Flask with SQLite, rules out GitHub Pages; a machine-learning demo points to Hugging Face Spaces or Streamlit Community Cloud.
-
How does hosting a static site differ from hosting an app that needs a server?
A static site is files the host sends as they are, so nothing has to wake up. A server app runs code for each request, so the host keeps a process for it, and an idle one may be asleep at the first request.
-
What does GitHub Pages serve, and what does it require on GitHub Free?
Static HTML, CSS and JavaScript from a repository, which on GitHub Free must be public. It cannot run a server such as a Flask app.
-
When do idle demos on Render and on Streamlit Community Cloud go to sleep?
A web service on Render's Free instance type spins down after 15 minutes without traffic; a Streamlit Community Cloud app sleeps after 12 hours without traffic.
-
Which plans in the hosting lesson rule out paid client work?
Vercel's Hobby plan, limited to personal use that is not commercial, and Render's Free instances.
-
Does a notebook demo need a host?
No. GitHub renders a notebook as static HTML, though without its interactive JavaScript plots, so the README should state the results in words.
-
How do you stop a sleeping host from hiding your project from a reader?
Put a short recording or screenshots in the README so the project is seen working within seconds, link the repository first and the live demo second, and note beside the link that the demo may take a minute to wake.
-
What data belongs in a public demo?
Only invented data, or data whose licence lets you publish it. Any stranger can open a demo, so no real person's name, number or record belongs in it.
Key takeaways
- The kind of demo decides the host: static files fit almost anywhere, a server rules out GitHub Pages, and an ML demo points to Spaces or Streamlit.
- A demo that few people visit is asleep when they come, so the README carries a recording and the link says the demo may take a minute to wake.
- Caps and terms can stop a demo too: read each plan’s limits, and keep paid work off plans meant for personal use.
Terms in this lesson
- spin-down
- A host stopping a service that has had no traffic for a while. The next request waits while the service starts again.
- static site
- A website made of files, such as HTML, CSS, JavaScript and images, that the host sends as they are, without running any code on the server for each request.
References
- What is GitHub Pages? (GitHub Docs)
- GitHub Pages limits (GitHub Docs)
- Creating a GitHub Pages site (GitHub Docs)
- Vercel Hobby Plan (Vercel Docs)
- Fair Use Guidelines (Vercel Docs)
- Vercel Functions Limits (Vercel Docs)
- Migrate a Python API from Render to Vercel (Vercel Knowledge Base)
- Credit-based pricing plans (Netlify Docs)
- How credits work (Netlify Docs)
- Deploy for Free (Render Docs)
- Spaces Overview (Hugging Face Docs)
- Spaces ZeroGPU: Dynamic GPU Allocation for Spaces (Hugging Face Docs)
- Manage your app (Streamlit Community Cloud) (Streamlit Docs)
- Working with non-code files (Jupyter notebooks) (GitHub Docs)
- About push protection (GitHub Docs)
- Removing sensitive data from a repository (GitHub Docs)
- Attribution 4.0 International (CC BY 4.0), deed (Creative Commons)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress