# How to Deploy Environments to Hugging Face Spaces Using the openenv CLI push Command

> Effortlessly deploy environments to Hugging Face Spaces with the openenv CLI push command. Streamline your deployment process and host your projects with ease.

- Repository: [Hugging Face/OpenEnv](https://github.com/huggingface/OpenEnv)
- Tags: how-to-guide
- Published: 2026-06-14

---

**The `openenv push` command transforms a local OpenEnv environment into a hosted Hugging Face Space by validating the environment structure, authenticating with Hugging Face, staging files, and uploading them to a Space repository.**

The openenv CLI provides a streamlined workflow for deploying interactive environments to Hugging Face Spaces. By using the `push` command, you can turn a local directory containing an [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml) manifest and Dockerfile into a fully hosted Space. This guide explains exactly how the deployment process works according to the huggingface/OpenEnv source code.

## How the openenv push Command Works

When you execute `openenv push`, the CLI follows a precise 10-step pipeline defined in [`src/openenv/cli/commands/push.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/push.py). Understanding these steps helps you troubleshoot deployment issues and optimize your configuration.

### 1. Environment Validation

The command first verifies that your directory contains the required OpenEnv structure. It calls `validate_env_structure` from [`src/openenv/cli/_cli_utils.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/_cli_utils.py) (lines 18‑31) to ensure the presence of [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml), [`README.md`](https://github.com/huggingface/OpenEnv/blob/main/README.md), and a valid Dockerfile. If any required files are missing, the CLI exits with a descriptive error before attempting network operations.

### 2. Manifest Parsing

The CLI reads [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml) to extract the environment name and configuration (lines 38‑42 of [`push.py`](https://github.com/huggingface/OpenEnv/blob/main/push.py)). This manifest drives subsequent decisions about repository naming and default variables.

### 3. Hugging Face Authentication

If you are not already logged in, the CLI invokes `whoami` and falls back to `login` to acquire a valid HF token (lines 46‑78). This ensures all subsequent API calls are authenticated without requiring manual token management.

### 4. Repository ID Resolution

When you omit the `--repo-id` argument, the CLI constructs a default identifier using the pattern `username/env-name`, combining your Hugging Face username with the environment name from the manifest (lines 20‑24). You can override this by providing an explicit `--repo-id` such as `my-org/my-game`.

### 5. Ignore Pattern Loading

To prevent uploading unnecessary files, the CLI loads default ignore patterns (`.git*`, `__pycache__`, `*.pyc`) and merges them with any custom `.gitignore`-style file via `_load_ignore_patterns` (lines 151‑188). These patterns filter the files sent to the Space.

### 6. Staging Directory Preparation

The CLI creates a temporary staging directory where it prepares the final upload payload. During this phase, `_prepare_staging_directory` (lines 211‑258) optionally rewrites the Dockerfile to set a custom base image or enable the web interface, and patches [`README.md`](https://github.com/huggingface/OpenEnv/blob/main/README.md) with the Space front-matter (`base_path: /web`) required for the Hugging Face UI.

### 7. Space Creation

If the target Space does not exist, `_create_hf_space` (lines 262‑281) calls `HfApi.create_repo` with `repo_type="space"` and applies your `--private` and `--hardware` flags (such as `t4-medium` or `cpu-basic`).

### 8. File Upload

The CLI uploads the staged directory using `api.upload_folder` (lines 292‑319), respecting the ignore patterns compiled earlier. If you pass `--create-pr`, the upload opens a Pull Request instead of committing directly to the main branch.

### 9. Variables and Secrets Configuration

Public variables (`--env-var`) and private secrets (`--secret`) are injected into the Space using `api.add_space_variable` and `api.add_space_secret` (lines 70‑84). Secret values are masked in logs to prevent accidental exposure.

### 10. URL Reporting

Finally, the CLI prints the URL of your newly created Space (lines 322‑328), allowing you to immediately access the deployed environment.

## Deployment Examples

The following examples demonstrate common deployment patterns using the openenv CLI.

### Deploy the Current Directory

Run this from within your OpenEnv folder to deploy with default settings (web UI enabled automatically):

```bash
cd my_openenv
openenv push

```

### Deploy to a Private Space with GPU

Specify the repository, privacy setting, and hardware accelerator:

```bash
openenv push --repo-id my-org/my-game \
             --private \
             --hardware t4-medium

```

### Use a Custom Base Image

Override the Dockerfile base image during the staging phase:

```bash
openenv push --base-image ghcr.io/huggingface/openenv-base:latest

```

### Deploy Multiple Instances

Create multiple Spaces at once for A/B testing or load distribution:

```bash
openenv push --count 3

```

### Inject Variables and Secrets

Pass public configuration variables and sensitive API keys (values are not logged):

```bash
openenv push -e MAX_STEPS=200 -e GAME=chess \
             --secret OPENAI_API_KEY=sk-********

```

### Deploy to an External Docker Registry

Instead of creating a Hugging Face Space, build and push directly to a container registry:

```bash
openenv push --registry docker.io/myuser \
             --no-interface

```

## Advanced Configuration Options

When using `--registry`, the CLI bypasses Space creation and executes the build logic from [`src/openenv/cli/commands/build.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/build.py), calling `_build_docker_image` and `_push_docker_image` to handle the container lifecycle directly. This is useful for integrating OpenEnv environments into existing Kubernetes workflows or third-party hosting platforms.

The `--count` flag triggers parallel deployments, generating sequentially named repositories (e.g., `my-env-1`, `my-env-2`) when a default repo ID is used. Each instance receives the same environment variables and secrets, but runs independently.

## Summary

- **`openenv push`** validates your environment via `validate_env_structure` before any network operations.
- The CLI stages files in a temporary directory, rewriting the Dockerfile and README to enable the web interface at `base_path: /web`.
- Authentication is handled automatically via `whoami` and `login` helpers.
- You can deploy to Hugging Face Spaces with custom hardware, privacy settings, and secrets using flags like `--hardware`, `--private`, and `--secret`.
- For container-only workflows, use `--registry` to push to external Docker registries instead of creating Spaces.

## Frequently Asked Questions

### What files must be present before running `openenv push`?

The command requires [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml) (the manifest), [`README.md`](https://github.com/huggingface/OpenEnv/blob/main/README.md), and a Dockerfile at the repository root or in a `server/` subdirectory. The `validate_env_structure` function in [`src/openenv/cli/_cli_utils.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/_cli_utils.py) enforces these requirements and will exit with an error if any are missing.

### How do I deploy to a private Space with specific hardware?

Use the `--private` flag combined with `--hardware` followed by the desired hardware identifier (e.g., `t4-medium`, `cpu-basic`). The CLI passes these parameters to `HfApi.create_repo` in the `_create_hf_space` function.

### Can I deploy to an external Docker registry instead of Hugging Face Spaces?

Yes. Specify `--registry` followed by the registry URL (e.g., `docker.io/myuser`). When this flag is present, the CLI invokes the build utilities from [`src/openenv/cli/commands/build.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/build.py) to construct and push the image directly, bypassing Space creation and the Hugging Face upload logic.

### How does the CLI handle sensitive environment variables?

Variables passed via `--secret` are set using `api.add_space_secret`, which stores them as encrypted secrets in the Space. These values never appear in CLI logs or the [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml) file, ensuring they remain secure according to the implementation in lines 70‑84 of [`push.py`](https://github.com/huggingface/OpenEnv/blob/main/push.py).