Deployment
Food Tracker (FastAPI)
Chapter 11 · Deployment
Every earlier chapter ran with uvicorn main:app --reload — a genuinely fine development server, and a genuinely wrong choice for real production traffic.
Running With Multiple Workers
Gunicorn manages several separate Uvicorn worker processes — a standard production pattern for FastAPI, giving real request-handling capacity beyond what a single process can provide, and automatically restarting a worker that crashes.
StaticFiles — the frontend and API have always shared one origin, in development and in production alike. There's no CORS middleware anywhere in this course, not because it was overlooked, but because Chapter 1's own architecture never created the cross-origin situation that would require it.
A Full-Circle Caveat on Chapter 1's Own Favorite Feature
Chapter 1 named automatic interactive docs at /docs as a genuine advantage none of this quartet's other courses get for free. Before a real deployment, that same feature deserves an honest second look:
/docs lets anyone browsing it try real API calls directly against the running app — fine, even valuable, during development; worth a deliberate decision, not an accidental default, before a real public launch. Disabling it conditionally, as above, keeps Chapter 1's own advantage intact during development while making its production exposure an explicit choice rather than something that just happens by default.
SQLite in Production: A Familiar Concern, and a New One
Food Tracker (React + Express)'s own deployment chapter named the risk of an ephemeral filesystem silently wiping the SQLite file on redeploy — the same risk applies here, for the same reason: confirm the deployment target keeps foodtracker.db on a volume that survives a restart.
This course introduces one genuinely new SQLite consideration the single-process Express deployment never had to face:
-w 4 above means four entirely separate operating-system processes, each with its own database connection to the same foodtracker.db file. SQLite handles multiple processes reasonably well for read-heavy workloads, but under genuine concurrent write contention across several processes at once, it can return real "database is locked" errors — a cost this course's own move to multiple worker processes trades away some of SQLite's single-process simplicity for. Chapter 10 already named that SQLite has no real connection pool the way a networked database does; this is the concrete, production-shaped consequence of that same limitation. At this app's own realistic single-household scale, simultaneous writes are genuinely rare, so a small worker count stays a reasonable choice — a busier real deployment would be a real, honest reason to move to PostgreSQL instead, exactly the same upgrade path Chapter 10 already named.
TLS Termination
Chapter 4's own camera access requires HTTPS in production. Gunicorn itself doesn't handle TLS certificates — a reverse proxy (nginx, the same pattern already covered in this site's own Nginx In Depth course) sits in front of it, terminating HTTPS and forwarding plain HTTP internally, the same general shape both the Django and Express siblings' own deployment chapters already used.
A Production Checklist
- Run with
gunicorn+ Uvicorn workers, never--reload. - Decide deliberately whether
/docsshould be public, and disable it if not. - Confirm the SQLite file lives on a volume that survives a redeploy.
- Keep worker count modest, or plan a PostgreSQL migration, if genuine concurrent writes are expected.
- Put a reverse proxy in front for TLS termination.
- Load real configuration (database path, environment name) from environment variables, not hardcoded values.
Where This Course Is Headed
One chapter left: a capstone tying every chapter into one complete, working app.
Hands-On Exercises
Explain why this course never needed CORS configuration anywhere, tracing the reason back to a decision made in Chapter 1.
📄 View solutionExplain why Chapter 1 named /docs as a genuine advantage, and why this chapter still recommends deliberately deciding whether to expose it in production rather than leaving the default as-is.
📄 View solutionExplain why running with multiple gunicorn workers introduces a SQLite concern that Food Tracker (React + Express)'s own single-process deployment never had to face, and how this connects back to a point Chapter 10 already made.
📄 View solutionChapter 11 Quick Reference
- Run with: gunicorn -k uvicorn.workers.UvicornWorker -w 4, never --reload in production
- No CORS anywhere: StaticFiles has served the frontend same-origin since Chapter 1 — a real simplicity payoff none of the three sibling courses share
- Full-circle caveat: /docs, Chapter 1's own praised feature, should be a deliberate production decision, not an accidental default
- Familiar SQLite risk: confirm a persistent volume, same as the Express sibling's own warning
- New SQLite risk: multiple worker processes writing to one file can hit real lock contention — a direct consequence of Chapter 10's own "no real connection pool" point
- TLS: a reverse proxy in front, same pattern as the Django and Express siblings
- Next chapter: Capstone