Overview
This is going to be a first in a series of articles focused on building projects. The end goal is to give you exposure to several technologies.
Learning subscriptions are plentyful. Many have options that provide a Cloud playground for you to utilize while learning. This can help lower your expenses. If you want persistence, you'll have to build something outside of these learning platforms.
I'm a firm believer in simple and cost effective. I'm not looking to take on monthly fees or even paying upfront for the year to save a percentage on the overall cost of a service. I'm also looking to avoid sustaining a home lab. I think a home lab option is great, but it can't be denied that this has trade offs (Power Consumption, Maintenance, Space Constraints, etc).
A low cost blog is something that shouldn't take long to stand up in the cloud. I can scale it if needed at a future date.
Prerequisites
Before you begin, ensure you have the following:
- A GitHub account with your FastAPI repository pushed and accessible
- A Render account (free to sign up)
- A 'requirements.txt' at the root of your repository
Connect Your GitHub Account to Render
You'll need to authorize Render to access your GitHub repositories.
- Navigate to the Render Dashboard
- Click New + in the top-right corner and select Web Service
- On the "Create a New Web Service" screen, click Connect GitHub
- You'll be redirected to GitHub's OAuth page — click Authorize Render
- Once authorized, Render will ask which repositories it can access. You can choose:
- All repositories — simplest option for personal accounts
- Only select repositories — recommended if you want tighter access control
- Select your FastAPI repository and confirm
Note: If you've already connected GitHub but don't see a specific repository, go to your GitHub settings under Applications → Authorized OAuth Apps and update the repository permissions for Render.
Create a New Web Service
With GitHub connected, you'll be taken back to Render to configure your service.
- Select your repository from the list
- Give your service a Name (e.g.,
flatfileblog) - Set the Region to whichever is closest to your expected audience (e.g.,
US East (Ohio)) - Set the Branch to
main(or whatever your production branch is) - Set the Root Directory — leave this blank since
requirements.txtlives at the repository root - Set the Runtime to
Python 3
Configure Build and Start Commands
Consider the file structure of your repository. Given the following example:
.
├── __init__.py
├── app
│ ├── main.py
│ ├── routers/
│ ├── content/
│ ├── static/
│ └── templates/
├── archive/
├── README.md
└── requirements.txt
Your FastAPI instance is defined by the main.py file located in the app/ directory.
Build Command
The build command runs once during deployment to install your dependencies.
pip install -r requirements.txt
Render runs this from the repository root. As long as the requirements.txt file is there, you should have a successful deployment.
Start Command
The start command tells Render how to launch your application. Since main.py is inside the app/ package, you reference it using Python module notation - app.main - and point Uvicorn to the app object with it.
uvicorn app.main:app --host 0.0.0.0 --port $PORT
I didn't take the time to get into the specifics of the FastAPI configuration (that will come in another blog post). There are a few things I would like to call out:
app.mainrefers to themain.pymodule inside theapp/directory. This works because there is an__init__.pyat the repository root, making the directory structure importable as a package.:appis the name of your FastAPI instance insidemain.py(e.g.,app = FastAPI()).--host 0.0.0.0is required so Render can bind the service to a public interface.$PORTis an environment variable that Render injects automatically - we shouldn't be hardcoding a port number.
Set the Instance Type to Free
Scroll down to the Instance Type section and select Free. This gives you:
- 512MB Ram
- Shared CPU
- 750 hours/month of runtime
- The service spins down after 15 minutes of inactivity (cold starts on first request)
For a low traffic project, this is completely acceptable. This cold start delay is usually 30-60 seconds, which is a worthwhile trade-off for zero hosting cost.
Add Environment Variables (If Needed)
If your application uses any environment-specific settings - database URLs, secret keys, API tokens - add them under the Environment section before deploying. These are injected as environment variables at runtime and kept out of your source code.
Deploy
Select Create Web Service. Render will:
- Clone your GitHub repository
- Run the build command (
pip install -r requirements.txt) - Start the server with the start command (
uvicorn app.main:app ..) - Assign your service a public URL like
https://your-service-name.onrender.com
You can monitor the deployment in real time through the Logs tab on the service dashboard.
Automatic Deploys from GitHub
Auto-Deploy is enabled by default on your connect branch. Every time you push a commit to main, Render will automatically rebuild and redeploy your service - no manual steps required. This is the git-commit-to-publish workflow in action.
If you'd prefer to control deploys manually, you can disable Auto-Deploy in the service settings and trigger them yourself from the dashboard or via Render's API.
Troubleshooting Common Issues
Module not found errors on startup
If Render can't find app.main, double-check that a __init__.py exists at the repository root. Without it, Python won't treat the directory as a package and the module path won't resolve correctly.
Port binding errors
Make sure your start command uses $PORT and not a hardcoded value like 8000. Render dynamically assigns a port and your app must bind to it.
Service not reachable after deploy
On the free tier, the service sleeps after inactivity. The first request after a sleep period will trigger a cold start — just wait 30–60 seconds and try again.
Dependencies not installing
Confirm that requirements.txt is committed to the root of your repository and that all packages including uvicorn and fastapi are listed in it.
Summary
Deploying a FastAPI project to Render's free tier is straightforward once you understand how the build and start commands map to your project structure. For a repository where main.py lives inside an app/ subdirectory, the key commands are:
| Setting | Value |
|---|---|
| Build Command | pip install -r requirements.txt |
| Start Command | uvicorn app.main:app --host 0.0.0.0 --port $PORT |
| Instance Type | Free |
| Auto-Deploy | Enabled (branch: main) |
The free tier's cold-start behavior is the main limitation, but for a personal portfolio or low-traffic blog, it's a non-issue. You get a live, publicly accessible URL, automatic GitHub deploys, and zero monthly cost.