DEV Community

Azhar Alvi
Azhar Alvi

Posted on

Phase 0 : Building My First FastAPI App: Setup, Git, and Secrets Done Right

Tagline: Commit small, commit often, write real messages.

Creating a hello-world app sounds easy — and it is. But doing it the right way, with proper git hygiene, isolated environments, and secrets handled safely from day one? That takes a bit more care. Here's what I actually did, step by step, and why.

Index

Introduction

I started learning backend dev properly this week, and today I got a hello-world FastAPI app running locally. Nothing fancy — one route, one JSON response — but I wanted to write down what actually happened along the way, because "install a package and run a command" always looks simpler in hindsight than it feels in the moment.

Structure of this log

  1. Create project folder → init git → .gitignore → virtual environment
  2. Connect to a GitHub repo
  3. Build and run a FastAPI hello-world app, explore /docs
  4. Set up a .env file for secrets and confirm it's gitignored
  5. Start this build log

Step 1: Project Foundations

Create the folder

mkdir my-project-1
cd my-project-1
Enter fullscreen mode Exit fullscreen mode

Initialize git first

git init
Enter fullscreen mode Exit fullscreen mode

Why first? So every file created from this point on is tracked from day one — no risk of forgetting to init later.

Create .gitignore before installing anything

cat > .gitignore << 'EOF'
venv/
__pycache__/
.env
.DS_Store
EOF
Enter fullscreen mode Exit fullscreen mode

Why before the virtual environment? If you create the venv first, git could briefly see hundreds of library files before you've excluded them. Doing this first avoids ever accidentally staging things you don't want tracked.

How this command works:

  • cat — normally reads and displays file content, but here it's not reading a file — it's about to receive typed input instead.
  • > — redirect operator. Instead of printing to the screen, the output is written into a file. Since .gitignore doesn't exist yet, this creates it.
  • << 'EOF' — a heredoc. It tells bash: "don't wait for a real file — treat everything typed next, up until a line that says exactly EOF, as the input text."
  • EOF (closing) — signals "stop, that's the end of the input."

Note: EOF isn't a special keyword — it's just a convention. You could use BANANA instead, and it would work identically: bash treats everything as raw text until it sees a line containing exactly that word. EOF ("End Of File") is used everywhere because it instantly signals intent to anyone reading the script.

Note: This heredoc syntax is bash-specific. PowerShell uses a different syntax (@" ... "@ | Out-File) — match the syntax to the shell you're actually in.

Create and activate the virtual environment

python -m venv venv
source venv/Scripts/activate
Enter fullscreen mode Exit fullscreen mode

What this does:

  • python -m venv venv — runs Python's built-in venv module, creating a folder (venv/) containing an isolated copy of Python and its own package directory.
  • source venv/Scripts/activate — activates it, redirecting your terminal's python/pip to point inside venv/ instead of your system-wide install. You'll know it worked when (venv) appears in your prompt.

Note: The folder is named Scripts/ on Windows and bin/ on Linux/macOS. If source venv/bin/activate fails with "No such file or directory," check which one actually exists with ls venv.

Install packages + freeze requirements

pip install requests
pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode

Why this matters: every time you install something new, freeze it into requirements.txt. This makes the exact dependency set shareable — anyone (including future-you) can recreate your environment with pip install -r requirements.txt.

First commit

touch README.md main.py      # or: New-Item README.md, main.py   (PowerShell)
git add .
git commit -m "Initial project setup"
Enter fullscreen mode Exit fullscreen mode

What makes a good commit message: it describes what changed and why — not just "update" or "fix stuff."

Connect to GitHub

Create a new, empty repository on GitHub first, then:

git remote add origin <your-repo-url>
git branch -M main
git push -u origin main
Enter fullscreen mode Exit fullscreen mode

Breaking this down:

Command What it does
git remote add origin <url> Registers a remote connection, nicknamed origin (convention), pointing at your GitHub repo's URL. No data moves yet — this just registers the address.
git branch -M main Renames your current branch to main (forcing it even if a branch with that name exists), matching what GitHub expects by default.
git push -u origin main Uploads your commits to GitHub for the first time. -u sets up tracking between local main and origin/main, so every push after this can just be git push.

Run this sequence once per project — right at the start, connecting a fresh local repo to a fresh GitHub repo.

The repeatable loop (used for every session after this)

source venv/Scripts/activate
# ... work, install packages ...
pip freeze > requirements.txt
git add .
git commit -m "clear description of change"
git push
deactivate
Enter fullscreen mode Exit fullscreen mode

The commit flow, in isolation

git status                          # check what changed
git add .gitignore                  # stage the change
git commit -m "clear description"   # commit with a real message
git push                            # push to GitHub
git log --oneline -1                # sanity check
Enter fullscreen mode Exit fullscreen mode

Step 2: Getting FastAPI Running Locally

Ensure the virtual environment is active

source venv/Scripts/activate
Enter fullscreen mode Exit fullscreen mode

Install FastAPI and Uvicorn

pip install fastapi uvicorn
pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode
  • FastAPI — lets you define API routes/endpoints in Python. It doesn't serve requests on its own — it needs an ASGI (Asynchronous Server Gateway Interface) server to actually run.
  • Uvicorn — a lightweight ASGI server that runs your app and listens for HTTP requests.

Create the app file

code .   # opens the current folder in VS Code
Enter fullscreen mode Exit fullscreen mode

Structure of main.py:

  • Import FastAPI
  • Create an application instance (app = FastAPI()) for Uvicorn to run
  • Use a decorator (@app.get("/")) so that a GET request to the root URL runs the function below it
  • Define the function to handle the request
  • Return the response (FastAPI auto-converts a Python dict to JSON)
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello, World!"}
Enter fullscreen mode Exit fullscreen mode

Start the server

uvicorn main:app --reload
Enter fullscreen mode Exit fullscreen mode
  • main:app — tells Uvicorn to look inside main.py for an object named app.
  • --reload — automatically restarts the server whenever you save a code change.

Visit http://127.0.0.1:8000 to see the JSON response.

Check the automatic docs

Visit http://127.0.0.1:8000/docs — FastAPI auto-generates a full interactive API explorer (Swagger UI / OpenAPI spec), built entirely from your route definitions. No docs code required.

A read-only alternative view is available at /redoc.


Step 3: Secrets — the .env File

Create .env

cat > .env << 'EOF'
APP_SECRET=super-secret-value-123
EOF
Enter fullscreen mode Exit fullscreen mode

Confirm it's actually ignored — don't just assume

git status                 # .env should not appear anywhere in the output
git check-ignore -v .env   # the definitive test
Enter fullscreen mode Exit fullscreen mode

git check-ignore -v reports exactly which line in which file is causing the file to be ignored, e.g.:

.gitignore:7:.env    .env
Enter fullscreen mode Exit fullscreen mode

Important: .gitignore only prevents git from tracking files it hasn't already started tracking. If a secret was committed before being added to .gitignore, it will still exist in your git history. Setting up the ignore rule before the first git add — which is what happened here — avoids this entirely.


Step 4: Start This Build Log

Keep two documents, for two different audiences:

  • BUILD_LOG.md (this file) — chronological, for future-me. What I did, what broke, what I learned. Terse is fine.
  • README.md — for other people (or future-me pretending to be someone else). What the project is and how to run it — a snapshot of current state, not a diary.

The most useful log entries capture the why, not just the what — especially for snags:

## 2026-07-16

- Set up project folder, git repo, and Python virtual environment
- Installed FastAPI + Uvicorn, built a hello-world app with a single GET / route
- Confirmed it runs locally and explored the auto-generated /docs (Swagger UI)
- Set up a .env file for secrets and confirmed it's properly gitignored
  (learned: .gitignore only blocks files git hasn't tracked yet — order matters)
Enter fullscreen mode Exit fullscreen mode

Commit it the same way as everything else:

git add BUILD_LOG.md
git commit -m "Start build log with first entry"
git push
Enter fullscreen mode Exit fullscreen mode

Key Habits to Keep

  • Commit small, commit often, write real messages — a message should answer "what changed and why," not just "update."
  • .gitignore before git add, always — order of operations is what actually protects secrets.
  • Freeze requirements on every install, not just at the end.
  • Log the "why" and the snags, not just the "what" — that's the part future-you will actually forget.

Top comments (0)