# Hugging Face Spaces and Gradio tutorial: build a demo and host it

> Gradio turns a Python function into a web page, and a Hugging Face Space hosts that page at a public address. This lesson builds a Gradio app, runs it on your machine, then publishes the docs' hot dog classifier to a Space. It also covers the plan you need, secrets, sleep and ZeroGPU, the shared GPU pool.

Mindket editors · Published 2026-11-05 · Updated 2026-11-05 · https://mindket.com/learn/hugging-face/gradio-spaces

## In short

- Confirm what your account may host before you choose how the Space runs.
- Hand credentials to the Space privately, because a public app's source is open to all.
- Put the model on the graphics card once, as the app boots, and request only the GPU seconds a call uses.
- Change the Gradio version on purpose in the README, then watch the rebuild.

## Before you start

You need Python 3.10 or later, a Hugging Face account and the Transformers setup from lesson 2. **Gradio** is an open-source Python package that builds a web page around any Python function: a form for its inputs and a panel for its outputs. Install it in your virtual environment with `pip install --upgrade gradio`.

A **Space** is a git repository on the Hub that runs an app. Every push rebuilds the app and restarts it. When you create one, you choose its **SDK**, the kind of app it runs: Gradio, Docker or static HTML.

Check your plan before you start. Static Spaces are free for everyone. Gradio and Docker Spaces run on compute, so creating one needs a paid plan: PRO for a personal account, Team or Enterprise for an organization.

There is one exception, and it shapes this lesson. A free personal account in good standing can host up to 2 Gradio Spaces on ZeroGPU, a shared GPU service. Good standing means a verified email and an account older than 30 days.

The Gradio quickstart still calls Spaces a place to host Gradio apps "for free". The Hub's Spaces page sets the rules, and on 5 November 2026 it said the opposite for Gradio Spaces outside ZeroGPU. Go by the Hub.

## Build a Gradio app on your machine

The quickstart's first app greets whoever types a name. Save the code as `app.py` and run `python app.py`. The app opens at `http://localhost:7860`, and `share=True` on the last line also creates a public link ending in `gradio.live`. While you edit, run `gradio app.py` instead. That is **hot reload** mode: the page reloads each time you save.

The `gr.Interface` class takes three core arguments. Its `fn` is the function to wrap. Its `inputs` hold one **component**, a form element such as a textbox or an image upload, for each argument of that function. Its `outputs` hold one component per return value, in order. You can name a component with a string such as `"textbox"` or create it as an object such as `gr.Textbox()`, and Gradio ships more than 30 of them.

A share link is the quickest way to show someone a demo, within limits. The traffic runs through Gradio's share servers, which only relay it to your computer and store nothing. Your machine does the work, so the link stops when you stop the app, and every link expires after a week. Anyone holding the link can use the app, so keep private data and risky actions out of the function.

To keep a demo to a few people, add a login. The sharing guide's example passes `auth=("admin", "pass1234")` to `launch()`, one username and password, and a list of such pairs also works. The guide calls this a basic layer of access control, with no multi-factor sign-in, rate limits or lockouts. It also needs third-party cookies, which Safari and Chrome's Incognito mode block by default.

Share links are off unless you ask for one, except in Google Colab notebooks, where Gradio creates them by itself. To show a local app to specific people without any public link, the guide suggests SSH port forwarding instead.

Two other classes cover other shapes. The `gr.ChatInterface` class builds a chat window around a function that answers messages. The `gr.Blocks` class lets you place components and chain events yourself, still in Python. This lesson stays with `Interface`.

````python
import gradio as gr

def greet(name):
    return "Hello " + name + "!"

demo = gr.Interface(fn=greet, inputs="textbox", outputs="textbox")

demo.launch(share=True)  # Share your demo with just 1 extra parameter 🚀
````

| Argument | What it takes | In the hot dog app |
| --- | --- | --- |
| `fn` | Any Python function | `predict`, which runs the classifier |
| `inputs` | One component per argument of `fn` | An image box that takes an upload or a webcam shot |
| `outputs` | One component per return value, in order | The image again, then a label showing the top 2 classes |
| `examples` | A nested list of sample inputs shown under the form | Not set |
| `title`, `description` | Text above the form | The title "Hot Dog? Or Not?" |

## Publish it on Hugging Face Spaces

The Spaces docs walk through a hot dog classifier, and its code follows as published. It loads `julien-c/hotdog-not-hotdog` with the Transformers pipeline from [lesson 2](https://mindket.com/learn/hugging-face/transformers-pipeline) and wraps it in an Interface. Give it a picture and it returns the picture with two labels, hot dog or not, each with a score.

The docs keep a finished copy of this Space at `NimaBoscarino/hotdog-gradio`, so you can compare your files with theirs. Because `huggingface_hub` comes preinstalled, a Space can also call the Inference Providers from lesson 3 instead of loading a model itself. That route needs less compute in the Space.

````python
import gradio as gr
from transformers import pipeline

pipeline = pipeline(task="image-classification", model="julien-c/hotdog-not-hotdog")

def predict(input_img):
    predictions = pipeline(input_img)
    return input_img, {p["label"]: p["score"] for p in predictions}

gradio_app = gr.Interface(
    predict,
    inputs=gr.Image(label="Select hot dog candidate", sources=['upload', 'webcam'], type="pil"),
    outputs=[gr.Image(label="Processed Image"), gr.Label(label="Result", num_top_classes=2)],
    title="Hot Dog? Or Not?",
)

if __name__ == "__main__":
    gradio_app.launch()
````

1. On the [Spaces page](https://huggingface.co/spaces), click **Create new Space**. Choose a name, an optional license and a visibility, then pick **Gradio** as the SDK.
2. Add a file named `requirements.txt` with two lines, `transformers` and `torch`. The Space installs them on every build. It already has `gradio`, `huggingface_hub`, `requests`, `datasets` and common Debian packages such as `ffmpeg`. For a system package it lacks, list the name in a `packages.txt` file, one per line, and the build installs each with `apt-get install`.
3. Add `app.py` with the code above. Thanks to its last two lines, the same file also runs on your machine with `python app.py`.
4. Push the files. Spaces are git repositories, so clone yours, commit and push after signing in with `hf auth login`. Or run `gradio deploy` in your app folder: it uploads every file there except those `.gitignore` lists, then starts the Space.
5. Wait for the build, then open the **App** tab. Upload a photo and read the two labels it returns.
6. Share the Space's address. Every later push rebuilds the app, so a fix goes live with the next build.

## Settings, secrets and a GPU with ZeroGPU

The YAML block at the top of the Space's `README.md` configures it, the way a model card's block describes a model. The `sdk` key says `gradio`. The `sdk_version` key holds the Gradio release, set to the latest one when you create the Space, and you edit it to upgrade. Other keys set `python_version`, which defaults to 3.10, plus `app_file`, `suggested_hardware` and `short_description`. If your app needs more than the default half hour to start, raise `startup_duration_timeout`.

Keys and settings go in the Space's **Settings**, as variables or secrets, never in `app.py`. Both reach your app as environment variables, and the table shows how they differ. A public Space's code is open to everyone, and the Hub scans Spaces for hard-coded secrets and warns their owners.

The default hardware, CPU Basic, gives 2 CPU cores, 16GB of RAM and 50GB of disk that does not survive a restart. That is enough for the hot dog classifier. A CPU Basic Space goes to sleep after 48 hours without visitors, and the next visitor wakes it. Paid hardware is billed only while the Space is starting or running, not during the build, and pausing the Space stops the bill. If a running Space starts to fail, the Hub suspends it and the billing stops too.

Upgraded hardware never sleeps by default. You can give it a custom sleep time in the settings, and it costs nothing while asleep. A Space that needs a GPU it cannot pay for can apply for a community GPU grant from the same sleep time settings.

**ZeroGPU** lends a Space a GPU only while a function needs one, from a shared pool of NVIDIA RTX Pro 6000 Blackwell cards. It works with the Gradio SDK only. The setup is three moves: pick ZeroGPU hardware in the Space settings, add `import spaces`, and put `@spaces.GPU` above each function that needs the GPU. Outside ZeroGPU the decorator does nothing, so the same file still runs on your laptop.

Load the model and move it to `cuda`, the NVIDIA GPU route from lesson 2, at the top of the file. A real GPU exists only inside the decorated functions, but the docs say startup placement is the efficient path, and moving the model inside a function is much slower. Each call gets 60 seconds of GPU by default. For a longer job, set a duration as in the snippet below. Shorter durations get better places in the queue. The duration can also be a function that takes the same inputs and returns the seconds, so a job with more steps can ask for more time.

The decorator asks for the `large` size by default, half a card with 48GB of video memory. Passing `size="xlarge"` gets the full card and its 96GB, at twice the quota cost and usually a longer wait. ZeroGPU supports Gradio 4 or later and PyTorch from version 2.8.0 on.

Every visitor spends their own daily GPU quota, shown in the chart, and it resets 24 hours after their first GPU use. The quota a visitor has left also sets their place in the queue. ZeroGPU does not support `torch.compile`, and the docs point to ahead-of-time compilation instead. A PRO account raises the hosting limit to 10 ZeroGPU Spaces.

The `hf` CLI from lesson 1 handles secrets and quotas from a terminal too. In the [CLI reference](https://huggingface.co/docs/huggingface_hub/package_reference/cli), `hf spaces secrets add username/my-space -s HF_TOKEN` adds a secret, and `hf spaces zero-gpu quota` shows your ZeroGPU quota in GPU-seconds.

````python
@spaces.GPU(duration=120)
def generate(prompt):
   return pipe(prompt).images
````

| Question | Variables | Secrets |
| --- | --- | --- |
| Meant for | Settings that are not sensitive, such as a model id | Access tokens, API keys and passwords |
| Who can read the value | Anyone, it is public | No one, and the settings page hides it once saved |
| Copied when someone duplicates the Space | Yes, filled in for them | No, they add their own |
| How the app reads it | As an environment variable, for example with `os.getenv` | The same way |

**Daily ZeroGPU time by account type** Minutes of GPU time a visitor can use per day across ZeroGPU Spaces. The PRO, Team and Enterprise quotas can be extended.

- Signed out: 2min
- Free account: 5min
- PRO account: **40min**
- Team member: 40min
- Enterprise member: 60min

Source: [Hugging Face Hub: Spaces ZeroGPU](https://huggingface.co/docs/hub/spaces-zerogpu) (read 2026-11-05)

## Lucain Pouget on Space templates, Lysandre on MCP Spaces

Lucain Pouget, who maintains `huggingface_hub`, [posted on X](https://x.com/Wauplin/status/2075242347760107797) on 9 July 2026 that version 1.23.0 builds a whole Space from an official template, such as JupyterLab or a Gradio chatbot, in one command. The [CLI reference](https://huggingface.co/docs/huggingface_hub/package_reference/cli) writes it as `hf repos create my-jupyterlab --type space --template SpacesExamples/jupyterlab`, and `hf spaces templates` lists the others. For a chat demo, start from the Gradio chatbot template and swap in your own function.

Lysandre, Chief Open-Source Officer at Hugging Face, [posted on X](https://x.com/LysandreJik/status/1931022549221056981) in June 2025 that any MCP Space could be picked through `hf.co/mcp` and used in an MCP client. He counted roughly 900 of them then, for images, video, audio and code.

The [HF MCP server page](https://huggingface.co/docs/hub/hf-mcp-server) now has you add them at [huggingface.co/settings/mcp](https://huggingface.co/settings/mcp) and restart the client. The **mcp-server** filter on the Spaces page lists the ones that serve MCP, so try a few before you build your own.

> Quickest way to spin up a complete Space.
>
> Lucain Pouget, Maintainer of huggingface_hub, [X](https://x.com/Wauplin/status/2075242347760107797) (read 2026-11-05)

[![Lucain Pouget (@Wauplin) on X, 9 July 2026. Quickest way to spin up a complete Space. huggingface_hub v1.23.0 lets you create a Space from an official template, such as JupyterLab or a Gradio chatbot, in just one command. The command is hf repos create my-lab --template jupyterlab. List what is available with hf spaces templates.](https://mindket.com/blog/shots/x-wauplin-space-templates.webp?v=41dca60620f7)](https://x.com/Wauplin/status/2075242347760107797)

Lucain Pouget on X, 9 July 2026

[![Lysandre (@LysandreJik) on X, 6 June 2025. Selecting any MCP Space through hf.co/mcp to use it in MCP Client is now possible. I see roughly 900 MCP Spaces already, with images (flux), video (ltx), audio, code and more.](https://mindket.com/blog/shots/x-lysandrejik-mcp-spaces.webp?v=5b7db37b2f3d)](https://x.com/LysandreJik/status/1931022549221056981)

Lysandre on X, 6 June 2025

> Screenshots of X's own embeds of the posts, taken on 5 November 2026, with the time in UTC. Select one to open the post on X.

## Common mistakes

- Putting a token in `app.py`. In a public Space anyone can read that file, so store the token as a secret.
- Forgetting `requirements.txt`. The build then has no `transformers` or `torch`, and the app stops at its first import.
- Asking for the `xlarge` GPU size by habit. It burns twice the daily quota of the default `large`, so keep it for jobs that need the whole card.
- Calling an outside service on an unusual port. A Space can only reach out through ports 80, 443 and 8080.
- Assuming a paid GPU works with no changes. Most Spaces do, but some need the CUDA build of their framework in `requirements.txt`, so check the Space logs after the upgrade.
- Pushing straight to ZeroGPU without a local run. The decorator is inert on your machine, so check the page with `gradio app.py` first and push once it works.
- Leaving `short_description` empty in the README. That line is what the Space's thumbnail shows, so it is what people read before they open the demo.

## Try it yourself

These two lines from the Spaces overview read a variable. Create the variable in **Settings** first, then add the lines to `app.py` in your Space.

````python
import os
print(os.getenv('MODEL_REPO_ID'))
````

- Add a variable named `MODEL_REPO_ID` set to `julien-c/hotdog-not-hotdog`. Where does the printed value show up?
- Change the pipeline line to take its model id from that variable. Could someone who duplicates your Space now switch models without touching the code?
- Add `examples=` to the Interface with two image files you committed to the repo. What appears under the form?
- Run the app locally with `gradio app.py`, change the title and save. Does the open page update by itself?
- Open [a public Space](https://huggingface.co/spaces) you like, pick **Duplicate this Space** from the three-dot menu, and note which variables come filled in. Duplicating follows the same plan rule as creating a Space, and the copy starts private on CPU Basic.

## Next course: Fine-tuning

That closes the loop: find a model, run it, call a bigger one and put a demo in front of people. The Fine-tuning course comes next. Its first lesson, [when to fine-tune](https://mindket.com/learn/fine-tuning/when-to-fine-tune), says when training a model on your own data beats a better prompt or RAG, and the course ends with your model on the Hub. The MCP course follows it. Gradio has a shortcut of its own: set `mcp_server=True` in `launch()` and the app's functions become MCP tools, which [build an MCP server in Python](https://mindket.com/learn/mcp/build-mcp-server-python) explains. A Space shows people your model, and an MCP server lets their assistants use your code.

## Check yourself

1. Which plan lets a personal account create a Gradio Space on CPU hardware?

   A. A free account
   B. PRO
   C. Any account with a verified email
   D. None, Gradio Spaces are always free

   Answer: B. Gradio and Docker Spaces need PRO for a personal account, and a free account in good standing can host up to 2 on ZeroGPU only.

2. Where should an API key for your Space go?

   A. In app.py
   B. In requirements.txt
   C. In a Space secret, read as an environment variable
   D. In the README YAML block

   Answer: C. Secrets stay private, are not copied when someone duplicates the Space, and reach the app as environment variables.

3. On ZeroGPU, where should the model be moved to cuda?

   A. At the top of the file, when the app starts
   B. Inside each @spaces.GPU function
   C. In requirements.txt
   D. Nowhere, ZeroGPU runs on the CPU

   Answer: A. The docs place models on cuda at module level, and moving them inside decorated functions is much less efficient.

4. How long does a Gradio share link last?

   A. One hour
   B. 24 hours
   C. Until you delete the Space
   D. Up to a week, and only while your computer runs the app

   Answer: D. Share links expire after a week, and your own machine does the work, so the link stops with the app.

## Frequently asked questions

### Can I keep the code of my Space private?

Yes. A private Space hides both the code and the app from everyone but you and your collaborators. A protected Space hides the code but keeps the app open at its hf.space address, and it needs a PRO, Team or Enterprise plan.

### Can I use Docker or plain HTML instead of Gradio?

Yes, both are SDK choices when you create a Space. A Docker Space runs any app you can put in a container and follows the same paid-plan rule as Gradio. A static Space serves HTML, CSS and JavaScript and costs nothing.

### How do I call my Space from my own code?

Through the "Use via API" link in the app's footer. Almost any Gradio app works as an API, and that page lists its endpoints with their parameters and example inputs. Gradio's Python client or its JavaScript client sends the requests.

### Can I embed a Space in my own website?

Yes. A Gradio Space can be embedded with Web Components or an HTML iframe. Public and protected Spaces also answer at their own hf.space address, which you can link to directly.

## Sources

- [Gradio: Quickstart](https://www.gradio.app/guides/quickstart) (read 2026-11-05)
- [Gradio: The Interface class](https://www.gradio.app/guides/the-interface-class) (read 2026-11-05)
- [Gradio: Sharing your app](https://www.gradio.app/guides/sharing-your-app) (read 2026-11-05)
- [Hugging Face Hub: Spaces overview](https://huggingface.co/docs/hub/spaces-overview) (read 2026-11-05)
- [Hugging Face Hub: Gradio Spaces](https://huggingface.co/docs/hub/spaces-sdks-gradio) (read 2026-11-05)
- [Hugging Face Hub: Handling Spaces dependencies](https://huggingface.co/docs/hub/spaces-dependencies) (read 2026-11-05)
- [Hugging Face Hub: Spaces configuration reference](https://huggingface.co/docs/hub/spaces-config-reference) (read 2026-11-05)
- [Hugging Face Hub: Using GPU Spaces](https://huggingface.co/docs/hub/spaces-gpus) (read 2026-11-05)
- [Hugging Face Hub: Spaces ZeroGPU](https://huggingface.co/docs/hub/spaces-zerogpu) (read 2026-11-05)
- [huggingface_hub: CLI reference](https://huggingface.co/docs/huggingface_hub/package_reference/cli) (read 2026-11-05)
- [Hugging Face Hub: HF MCP Server](https://huggingface.co/docs/hub/hf-mcp-server) (read 2026-11-05)
- [Lucain Pouget on X: create a Space from a template in huggingface_hub v1.23.0](https://x.com/Wauplin/status/2075242347760107797) (read 2026-11-05)
- [Lysandre on X: MCP Spaces through hf.co/mcp](https://x.com/LysandreJik/status/1931022549221056981) (read 2026-11-05)

[Browse MCP servers](https://mindket.com/mcp-servers)
