In Part 1, we built a full-stack CRUD (Create, Read, Update, Delete) application using FastAPI for the backend and React.js for the frontend. Now, let’s make it live on Render.com, a free and beginner-friendly platform!
This guide will walk you through deploying the FastAPI backend as a Web Service and the React frontend as a Static Site.
We’ll also fix common errors (like CORS and import issues) and share best practices to ensure a smooth deployment.
This article is for absolute beginners. We assume you’ve completed the tutorial, have your project in a Git repository (e.g., GitHub), and are ready to deploy.
Don’t worry—we’ll explain every step clearly!
Prerequisites
Before starting, ensure you have:
- A Render.com account (sign up at render.com).
- Your project pushed to a Git repository (GitHub, GitLab, or Bitbucket).
Your project structure should look like:
my-crud-app/
├── backend/
│ ├── main.py
│ ├── models.py
│ ├── schemas.py
│ ├── database.py
│ ├── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── App.js
│ │ ├── App.css
│ ├── package.json
│ ├── public/
Basic Git commands (e.g., git add, git commit, git push).
The backend dependencies listed in requirements.txt (see below).
If you don’t have requirements.txt, create it in backend:
cd backend
pip install fastapi uvicorn sqlalchemy databases aiosqlite python-dotenv
pip freeze > requirements.txt
This generates a file like:
fastapi==0.111.1
uvicorn==0.30.6
sqlalchemy==2.0.31
databases==0.9.0
aiosqlite==0.20.0
python-dotenv==1.0.1
Step 1: Deploy the FastAPI Backend as a Web Service
The backend is the server that handles CRUD operations (e.g., storing items in a database).
Render’s Web Service runs your FastAPI app.
1.1 Prepare the Backend
1. Fix Imports in main.py:
The tutorial uses relative imports (from . import models, schemas, database), which can cause errors on Render like “ImportError: attempted relative import with no known parent package.” You have two options to fix this:
Option 1: Use Absolute Imports with backend:
Change the import line in backend/main.py:
from backend import models, schemas, database
This assumes backend/ is your module name.
Option 2: Use init.py for Package Structure:
Create an empty init.py file in backend/ to make it a Python package:bash
cd backend
touch __init__.py # macOS/Linux (or echo. > __init__.py on Windows)
Keep the relative import in main.py:python
from . import models, schemas, database
Add an environment variable in Render (see Step 1.2) to set PYTHONPATH.
Recommendation: Use Option 1 (absolute imports) for simplicity—it works without extra files or environment variables.
If you prefer Option 2, we’ll configure it below.
Commit changes:
cd backend
git add main.py # And __init__.py if using Option 2
git commit -m "Fix imports for deployment"
git push origin main
Verify requirements.txt:
Confirm it includes all dependencies (listed above). If missing, regenerate:
cd backend
source venv/bin/activate # macOS/Linux (or .venvScriptsactivate on Windows)
pip freeze > requirements.txt
git add requirements.txt
git commit -m "Add requirements.txt"
git push origin main
Test Locally:
Run the backend:
uvicorn main:app --host 0.0.0.0 --port 8000
Visit http://localhost:8000/docs to see the FastAPI Swagger UI.
Test POST /items/ with a sample item: {„name“: „Test“, „description“: „Test item“}. If using Option 2, set:
export PYTHONPATH=$PWD # macOS/Linux (or set PYTHONPATH=%CD% on Windows)
1.2 Deploy on Render
(1). Create a Web Service:
Log in to Render.com
Click New > Web Service.
Connect your Git repository (containing backend/ and frontend/).
Set Root Directory to backend/ (if in a monorepo).
(2). Configure Settings:
- Name: e.g., my-crud-api.
- Environment: Python 3.
- Branch: main.
- **Build **Command: pip install -r requirements.txt.
- Start Command:
- For Option 1 (absolute imports): uvicorn main:app –host 0.0.0.0 –port $PORT.
- For Option 2 (init.py): uvicorn backend.main:app –host 0.0.0.0 –port $PORT.
- Instance Type: Free.
-
Environment Variables (for Option 2 only):
Key: PYTHONPATH
Value: /opt/render/project/src/backend - If using a database other than SQLite, add **DATABASE_URL **later (Step 4).
- Deploy:
- Click Create Web Service.
- Check Logs for errors (e.g., missing dependencies or import issues).
- Get the URL (e.g., https://my-crud-api.onrender.com).
- Visit /docs to confirm the API is live.
Step 2: Deploy the React Frontend as a Static Site
The frontend is your React app, served as static files after building. Render’s Static Site hosting is ideal.
2.1 Prepare the Frontend
Update API Base URL:
In frontend/src/App.js, use an environment variable to avoid hardcoding the backend URL:
const API_BASE = (process.env.REACT_APP_API_URL || 'http://localhost:8000').replace(//+$/, '');
- The .replace(//+$/, “) prevents double slashes (e.g., //items/).
- Update Axios calls to use /items (no trailing slash):javascript
const response = await axios.get(`${API_BASE}/items`);
const response = await axios.post(`${API_BASE}/items`, { name, description });
Commit:
cd frontend
git add src/App.js
git commit -m "Update API base URL"
git push origin main
Test Locally:
cd frontend
export REACT_APP_API_URL=https://my-crud-api.onrender.com # Your backend URL
npm install
npm start
Open http://localhost:3000, create an item, and check the Network tab (F12) to ensure requests go to https://my-crud-api.onrender.com/items.
2.2 Deploy on Render
Create a Static Site:
- In the same Render project, click New > Static Site.
- Connect the same Git repository.
- Set Root Directory to ** frontend/.**
Configure Settings:
- Name: e.g., my-crud-frontend.
- Branch: main.
- Build Command: npm install && npm run build.
- Publish Directory: build.
-
Environment Variables:
Key: REACT_APP_API_URL
Value: https://my-crud-api.onrender.com (no trailing slash).
Deploy:
- Click Create Static Site.
- Check build logs for errors (e.g., missing react-scripts in package.json).
- Get the URL (e.g., https://my-crud-frontend.onrender.com).
Step 3: Fix CORS for Frontend-Backend Communication
Since the frontend and backend are on different domains, the backend must allow the frontend’s domain via CORS.
(1).
Update main.py:
In backend/main.py, add the frontend URL to CORS:
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://localhost:3000",
"https://my-crud-frontend.onrender.com" # Your frontend URL
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
(2).
Redeploy Backend:
cd backend
git add main.py
git commit -m "Add frontend URL to CORS"
git push origin main
Redeploy in Render if auto-deploy is off.
(3).
Test CORS:
Visit https://my-crud-frontend.onrender.com.
In Developer Tools (F12) > Network tab, check that POST /items succeeds (201 Created).
Step 4: Handle Database Persistence
The tutorial uses SQLite, which loses data on Render due to its ephemeral filesystem. Use Render’s PostgreSQL for production.
(1). Create a PostgreSQL Database:
In Render, click New > PostgreSQL.
Set a name (e.g., my-crud-db) and create.
Copy the Internal Database URL from the Info tab.
(2). Update Backend:
In backend/database.py:
from sqlalchemy import create_engine
import os
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./sql_app.db")
engine = create_engine(DATABASE_URL)
Add to requirements.txt:
psycopg2-binary==2.9.9
In Render Web Service, add:
- Key: DATABASE_URL
- Value:
Redeploy backend.
Resolving Common Errors
Here are beginner-friendly fixes for issues you might face.
Error 1: CORS Policy Blocks Requests
Symptoms: Browser console shows: “Access to XMLHttpRequest at ‘https://my-crud-api.onrender.com/items’ from origin ‘https://my-crud-frontend.onrender.com’ has been blocked by CORS policy.”
Fix:
- Add the frontend URL to allow_origins in main.py.
- Test with allow_origins=[„*“] temporarily, then revert to specific domains.
- Redeploy backend and check Network tab.
Error 2: Double Slash in URL (e.g., //items/)
Symptoms: Requests fail with 404 due to https://my-crud-api.onrender.com//items/.
Fix:Ensure App.js strips trailing slashes:javascript
const API_BASE = (process.env.REACT_APP_API_URL || ‚http://localhost:8000′).replace(//+$/, “);
Set REACT_APP_API_URL without a trailing slash in Render.
Redeploy frontend.
Error 3: Backend Import Error
Symptoms: Render logs show “ImportError: attempted relative import with no known parent package.”
Fix:
Use
-
Option 1: Change to from backend import models, schemas, database.
Or - Option 2: Add init.py to backend/ and set PYTHONPATH=/opt/render/project/src/backend in Render.
- Redeploy backend.
Error 4: Data Resets on Redeploy
Symptoms: Items disappear after redeploying.
Fix: Use PostgreSQL (Step 4) instead of SQLite.
Error 5: Slow Backend Response
Symptoms: First request takes 10-30 seconds.
Fix: Normal for Render’s free tier. Upgrade to paid (~$7/month) for always-on, or warn users of delays.
Best Practices for Beginners
(1). Use Environment Variables:
Store URLs (e.g., REACT_APP_API_URL) in Render’s environment variables.
(2). Test Locally:
- Run backend (uvicorn main:app) and frontend (npm start) with deployed URLs.
- Check Network tab (F12) for errors.
(3). Check Logs:
Use Render’s Logs tab to debug build or runtime issues.
(4). Validate Inputs:
Prevent empty form submissions:
const createItem = async () => {
if (!name || !description) {
alert('Name and description are required');
return;
}
// ... Axios POST
};
(5). Version Control:
Commit with clear messages: git commit -m „Fix CORS“.
(6). Secure CORS:
Only allow specific origins (not [„*“]) in production.
(7). Monitor Performance:
Consider paid tiers for faster responses.
Testing Your Deployed App
- Visit https://my-crud-frontend.onrender.com.
- Test CRUD operations:Create, read, update, delete items.
- Check Network tab (F12) for request success (200/201 status).
- Debug errors using Render logs and browser console.
Congratulations!Your full-stack CRUD app is live on Render! You’ve deployed the FastAPI backend and React frontend, fixed common issues, and learned best practices. Share your app’s URL and explore adding features like custom domains or user authentication.
If you need help, check Render’s docs or comment below. Happy deploying!