> Source URL: /unit-3/resources/render-deploy.guide
# Deploy Your Flask App to Render

This guide walks you through putting your Flask app on the internet so anyone can visit it. You will use **Render**, a free hosting service that connects to your GitHub repo. Every time you push new code from Codespaces, Render will automatically update your live site.

By the end you will have a real URL like `https://your-app-name.onrender.com` that you can share with anyone.

---

## Before You Start

Make sure these are true:

- Your app runs in Codespaces when you type `uv run flask --app app run --debug` (or `python app.py`) and you can see it in the browser.
- You have an `app.py` file in the root of your project (not inside a folder).
- You have a `templates/` folder with your HTML files next to `app.py`.
- Your Flask variable is named `app` — i.e. `app = Flask(__name__)` inside `app.py`.

If your app does not run yet, fix that first. This guide is only for apps that already work.

---

## Step 1 — Make Sure Dependencies Are in `uv`

Render can use the same `uv` setup you use in Codespaces. That means your dependencies should live in `pyproject.toml` and `uv.lock`.

1. In the terminal, install `gunicorn` with `uv`:

```bash
uv add gunicorn
```

`gunicorn` is a production server that Render uses to run your app (instead of the simple development server you use locally).

2. If your app imports other packages, add them with `uv add` too. Some common examples:

```bash
uv add python-dotenv
uv add resend
uv add requests
```

3. Confirm that `pyproject.toml` and `uv.lock` are in the same folder as `app.py` — not inside `templates/` or any other folder.

---

## Step 2 — Create `render.yaml`

This file tells Render exactly how to build and start your app. Without it you would have to type all of this into the Render website by hand.

1. Create another new file in the same root folder as `app.py`.
2. Name it exactly: `render.yaml`
3. Paste this in and save (change `your-app-name` to whatever you want the URL to be):

```yaml
services:
  - type: web
    name: your-app-name
    env: python
    plan: free
    buildCommand: uv sync --frozen && uv cache prune --ci
    startCommand: uv run gunicorn app:app
    autoDeploy: true
```

Here is what each line means:

| Line                  | What it does                                        |
| --------------------- | --------------------------------------------------- |
| `type: web`           | Tells Render this is a website                      |
| `name: your-app-name` | The name that shows up on Render's dashboard        |
| `env: python`         | Tells Render your app is Python                     |
| `plan: free`          | Uses the free tier (no credit card needed)          |
| `buildCommand`        | Installs your packages from `uv.lock`               |
| `startCommand`        | Starts your app using gunicorn through `uv`         |
| `autoDeploy: true`    | Deploys automatically every time you push to GitHub |

### If your app uses environment variables (API keys, secrets)

If your app loads anything from a `.env` file (API keys like `RESEND_API_KEY`, SMTP passwords, etc.), add an `envVars` block so Render knows they exist. You set the actual values in the Render dashboard — never in the repo.

```yaml
services:
  - type: web
    name: your-app-name
    env: python
    plan: free
    buildCommand: uv sync --frozen && uv cache prune --ci
    startCommand: uv run gunicorn app:app
    autoDeploy: true
    envVars:
      - key: RESEND_API_KEY
        sync: false
      - key: OWNER_EMAIL
        sync: false
```

`sync: false` means "don't read this from the file, ask me in the dashboard." That's how secrets stay out of Git.

---

## Step 3 — Push Your Changes to GitHub

Now you need to send these files to GitHub so Render can see them.

1. Click the **Source Control** icon in the left sidebar (it looks like a branch/fork shape — the third icon from the top).
2. You should see `render.yaml` listed under **Changes**. You may also see `pyproject.toml` and `uv.lock` if `uv add gunicorn` changed them.
3. Click the **+** button next to each changed file to stage it (this tells Git you want to include it).
4. In the **Message** box at the top, type: `add render deploy files`
5. Click the **Commit** button (the checkmark).
6. Click **Sync Changes** to push your code up to GitHub.

If Codespaces asks you to confirm, click **OK**.

Go to your repo on GitHub and confirm that `pyproject.toml`, `uv.lock`, and `render.yaml` appear in the file list.

---

## Step 4 — Create a Render Account

1. Open a new browser tab and go to [render.com](https://render.com).
2. Click **Get Started for Free** (or **Sign Up**).
3. Choose **Sign up with GitHub**. This is the easiest option because Render will already be connected to your code.
4. GitHub will ask you to authorize Render. Click **Authorize Render**.
5. You may need to grant Render access to the organization that owns your class repo. If you see a screen asking about organization access, make sure your class organization is checked, then click **Grant** or **Approve**.

You now have a Render account connected to your GitHub.

---

## Step 5 — Create a Web Service on Render

1. On the Render dashboard, click the **New +** button (top right area).
2. Choose **Web Service**.
3. Render will show a list of your GitHub repos. Find your final project repo and click **Connect**.
   - If you do not see it, click **Configure account** and make sure Render has access to the organization that owns your repo.
4. Render should auto-fill most settings from your `render.yaml`. Double-check these:
   - **Name:** `your-app-name` (or whatever you want your URL to be)
   - **Environment:** `Python`
   - **Build Command:** `uv sync --frozen && uv cache prune --ci`
   - **Start Command:** `uv run gunicorn app:app`
   - **Plan:** `Free`
5. If you added `envVars` to `render.yaml`, scroll down to the **Environment Variables** section and paste in the actual values (e.g. your real `RESEND_API_KEY`). These are stored on Render, not in Git.
6. Click **Create Web Service**.

Render will now start building your app. This takes a minute or two.

---

## Step 6 — Watch the Deploy and Test Your App

1. After clicking **Create Web Service** you will see a log of everything Render is doing. Look for messages like:
   - `Running 'uv sync'...`
   - `Build successful`
   - `Your service is live`
2. Once the deploy finishes, Render shows your live URL near the top of the page. It will look something like: `https://your-app-name.onrender.com`
3. Click that link. You should see your app — the same one you see in Codespaces, but now on the real internet.
4. Click through the core flow of your app (submit a form, click the main buttons, view any pages your demo depends on). Make sure everything works.

If something goes wrong, skip down to the **Troubleshooting** section below.

---

## Step 7 — How Updates Work From Now On

Render is set to **auto-deploy** your app. That means the workflow going forward is simple:

1. **Edit your code** in Codespaces like you normally do.
2. **Commit** your changes (Source Control → type a message → click Commit).
3. **Sync Changes** to push to GitHub.
4. **Render automatically picks up the change** and redeploys your app. You do not need to go to the Render website.

Your live site updates in about 1–2 minutes after you push. You can watch the progress on your Render dashboard if you want, but you do not have to.

```
Edit code → Commit → Sync → Render auto-deploys → Live site updates
```

That's it. Every time you improve your app and push the code, the world sees the new version.

---

## Important: SQLite on Render's Free Tier

If your app saves data to a SQLite file (e.g. `data/leads.db`, `instance/app.db`), know this:

**Render's free tier has an ephemeral filesystem.** Every time Render redeploys your app — including every push to GitHub — the disk is wiped and recreated. Any rows you saved through the live site will disappear on the next deploy.

For demo day, this is usually fine — you can submit a few fresh test rows right before your demo and they'll be there. But don't expect your live site to be a real data store.

The proper fix is to attach a **Render Disk** (paid) or switch to a hosted database like Render's Postgres free tier. See [Render Disks docs](https://render.com/docs/disks) if you need this.

---

## Troubleshooting

### "ModuleNotFoundError: No module named 'flask'" (or any other module)

Your `pyproject.toml` is missing a package, or `uv.lock` was not committed. In Codespaces, add the missing package with `uv`:

```bash
uv add package-name
```

For example: `uv add resend`, `uv add python-dotenv`, or `uv add requests`. Then commit `pyproject.toml` and `uv.lock`, push, and Render will rebuild.

### "Application failed to respond" or the page won't load

This usually means the start command is wrong. Go to your Render dashboard → your service → **Settings**, and check that the **Start Command** is:

```
uv run gunicorn app:app
```

The first `app` is your filename (`app.py`). The second `app` is the Flask variable inside that file (`app = Flask(__name__)`). Both must match. If your file is named `main.py` and your Flask variable is still `app`, use `uv run gunicorn main:app`.

### The app loads but looks unstyled (no colors, no layout)

If you use a CDN for your CSS framework (Bootstrap, Tailwind, etc.), make sure the `<link>` or `<script>` tag is still in your HTML `<head>`. For Bootstrap:

```html
<link
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
  rel="stylesheet"
/>
```

If you have a local `static/style.css`, make sure the `static/` folder is committed to GitHub.

### "TemplateNotFound" or "No such file or directory: templates/..."

Make sure your `templates/` folder is committed to GitHub. In the Source Control panel in Codespaces, check that every file under `templates/` has been pushed. If any show under **Changes**, stage and commit them.

### "Internal Server Error" when using environment variables

Your code is calling `os.environ["RESEND_API_KEY"]` (or similar) and the variable isn't set on Render. Go to your service → **Environment** tab → add the key and its value → **Save Changes**. Render will redeploy.

Common mistake: you committed the key name in `render.yaml` with `sync: false` but forgot to paste the actual value into the dashboard.

### Render says "Build failed" but you don't know why

Read the full build log on the Render dashboard. Look for red text or lines starting with `ERROR`. The most common cause is a missing dependency in `pyproject.toml` or a missing `uv.lock`. If your app imports something besides `flask`, add it with `uv add package-name`, then commit and push both `pyproject.toml` and `uv.lock`.

### The free plan is slow to start

Render's free tier puts your app to sleep after 15 minutes of no traffic. The first visit after it sleeps takes 30–60 seconds to wake up. This is normal. After it wakes up, it stays fast until it goes idle again.

For demo day, open your site 1–2 minutes before you present so it's awake when the class sees it.

---

## Quick Reference

| What                 | Value                                                                           |
| -------------------- | ------------------------------------------------------------------------------- |
| **Render dashboard** | [dashboard.render.com](https://dashboard.render.com)                            |
| **Build command**    | `uv sync --frozen && uv cache prune --ci`                                       |
| **Start command**    | `uv run gunicorn app:app`                                                       |
| **Live URL pattern** | `https://your-app-name.onrender.com`                                            |
| **Free tier limits** | 750 hours/month, sleeps after 15 min idle, ephemeral disk                       |
| **Secrets**          | Set in dashboard → Environment tab. Never commit `.env`. Commit `.env.example`. |

---

## Related Resources

- [Flask Setup Guide](./flask-setup.guide.md)
- [Render Python docs](https://render.com/docs/deploy-flask)
- [Render Disks (persistent storage)](https://render.com/docs/disks)


---

## Backlinks

The following sources link to this document:

- [Render Deploy Guide](/unit-3/project-paths/lucas-w/lucas-w-2026-04-23.guide.llm.md)
- [Render Deploy Guide](/unit-3/project-paths/duward-a/duward-a-2026-04-24.guide.llm.md)
