> ## Documentation Index
> Fetch the complete documentation index at: https://docs.playflowcloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Image Builds

> Deploy game servers from your own Docker images.

# Docker Image Builds

PlayFlow supports two ways to deploy your game server: uploading a ZIP of your server build, or importing a pre-built Docker image. This guide covers the Docker image approach, which gives you full control over your server environment and enables tighter CI/CD integration.

## How It Works

When you import a Docker image, PlayFlow pulls it from your container registry and makes it available for server launches. Servers started from a Docker image build skip the ZIP download and extraction step entirely -- the image is ready to run immediately.

> [!NOTE]
>
> Docker image builds are ideal for teams that already have a containerized build pipeline. If you are new to containers or prefer a simpler workflow, the [ZIP upload method](https://docs.playflowcloud.com/unity/game-servers.md) handles containerization for you automatically.

## Prerequisites

Before you begin, make sure you have:

* A PlayFlow project with a **server API key** (the `pf_`-prefixed key from **Project Settings** on the dashboard). Keep it server-side — in CI, store it as a secret. Client keys (`pfclient_`) are meant for game builds and cannot manage builds.
* A Docker image pushed to an accessible container registry (Docker Hub, GitHub Container Registry, AWS ECR, etc.)
* If your registry is private, the credentials to pull the image

## Importing a Docker Image

**1. Push your image to a container registry**

Build and push your game server image to any Docker-compatible registry. Make sure the image contains everything your server needs to run.

```bash theme={null}
docker build -t registry.example.com/my-game-server:v1.0 .
docker push registry.example.com/my-game-server:v1.0
```

**2. Import the image into PlayFlow**

Call the Docker image import endpoint with your image URL and, optionally, registry credentials and an executable path.

```bash curl (public registry) theme={null}
curl -X POST https://api.computeflow.cloud/api/v3/builds/docker-image \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-server-build",
    "image_url": "registry.example.com/my-game-server:v1.0"
  }'
```

```bash curl (private registry) theme={null}
curl -X POST https://api.computeflow.cloud/api/v3/builds/docker-image \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-server-build",
    "image_url": "registry.example.com/my-game-server:v1.0",
    "executable_path": "/app/server",
    "registry_credentials": {
      "username": "your-username",
      "password": "your-access-token"
    }
  }'
```

**3. Wait for processing to complete**

The build is created with status `processing`. PlayFlow pulls the image and prepares it for server launches. You can poll the build status endpoint or watch for updates on the dashboard.

```bash theme={null}
curl https://api.computeflow.cloud/api/v3/builds/BUILD_ID \
  -H "api-key: YOUR_API_KEY"
```

When processing finishes, the status changes to `ready`.

**4. Launch a server from the build**

Once the build is ready, start a server using it just like any other build. PlayFlow uses the Docker image directly -- no ZIP download or extraction required.

You reference a build **by the name you gave it at import**, not by its ID. Pass that name as `version_tag`, and always include a `name` and `region` (both required):

```bash theme={null}
curl -X POST https://api.computeflow.cloud/api/v3/servers/start \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-match-1",
    "region": "us-east",
    "version_tag": "my-server-build"
  }'
```

> [!NOTE]
>
> `version_tag` is the build name you chose when importing (here, `my-server-build`) — PlayFlow launches the latest `ready` build with that name. To pin an exact build version, also pass `version` (a number). The `BUILD_ID` you polled in the previous step is only for checking build status; it is not used to launch a server.

> [!TIP]
>
> Read the connection host and port from the `network_ports[]` array in the start response (each entry has `host` and `external_port`) rather than assuming a fixed port — PlayFlow allocates the external port dynamically, and it differs from your internal port.

## Request Body Reference

| Field | Type | Required | Description |
| :- | :- | :- | :- |
| `name` | string | No (defaults to `"default"`) | The name for this build — this is what you pass as `version_tag` when launching a server. Builds with the same name auto-increment their version number. |
| `image_url` | string | Yes | The full image URL including tag (e.g., `registry.example.com/my-server:v1.0`). |
| `executable_path` | string | No | The path to the server executable inside the container. Only needed if it cannot be inferred automatically. |
| `registry_credentials` | object | No | Credentials for pulling from a private registry. |
| `registry_credentials.username` | string | Yes (if credentials provided) | Registry username or service account name. |
| `registry_credentials.password` | string | Yes (if credentials provided) | Registry password, access token, or personal access token. |

## Docker Image vs. ZIP Upload

> [tab] Docker Image
>
> **Best for:** advanced users, custom runtimes, CI/CD pipelines, non-standard server setups.
>
> * You build and manage the Docker image yourself
> * Full control over the base image, dependencies, and runtime environment
> * Faster server startup since the image is pre-built
> * Integrates naturally with CI/CD -- push to your registry, then import to PlayFlow
> * Supports any language, framework, or game engine

> [tab] ZIP Upload
>
> **Best for:** simple deployments, Unity/Godot builds, getting started quickly.
>
> * Upload a ZIP of your server binary and PlayFlow handles containerization
> * No Docker knowledge required
> * Great for standard Unity or Godot dedicated server builds
> * PlayFlow manages the image build and optimization

## CI/CD Integration

Docker image builds fit naturally into automated pipelines. Here is an example GitHub Actions workflow that builds your server image, pushes it to a registry, and imports it into PlayFlow:

```yaml github-actions.yml theme={null}
name: Deploy Game Server
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build and push Docker image
        run: |
          docker build -t ghcr.io/${{ github.repository }}/server:${{ github.sha }} .
          echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
          docker push ghcr.io/${{ github.repository }}/server:${{ github.sha }}

      - name: Import to PlayFlow
        run: |
          curl -X POST https://api.computeflow.cloud/api/v3/builds/docker-image \
            -H "api-key: ${{ secrets.PLAYFLOW_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{
              "name": "production-server",
              "image_url": "ghcr.io/${{ github.repository }}/server:${{ github.sha }}",
              "registry_credentials": {
                "username": "${{ github.actor }}",
                "password": "${{ secrets.GHCR_TOKEN }}"
              }
            }'
```

## Tips

> [!WARNING]
>
> Always use a specific image tag (e.g., `:v1.0` or a commit SHA) rather than `:latest`. This ensures that your servers run the exact version you tested, and makes rollbacks straightforward.

* **Keep images small.** Smaller images pull faster, which reduces build processing time. Use multi-stage builds and minimal base images (e.g., `debian-slim`, `alpine`) where possible.
* **Signal readiness from your server.** PlayFlow does not probe a custom health endpoint in your game. Server readiness is reported by the PlayFlow agent sidecar via a status callback once your game process is up, so make sure your server starts and binds its ports promptly.
* **Test locally first.** Run your image with `docker run` before importing to PlayFlow to catch configuration issues early.

***

## Next Steps

> [card] [Server Regions](https://docs.playflowcloud.com/fundamentals/regions.md)
>
> Choose the best deployment region for your players.

> [card] [Pricing & Instance Types](https://docs.playflowcloud.com/fundamentals/plan-instance-types.md)
>
> Review available compute sizes and pricing.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.