Skip to main content
fal Serverless runs custom containers. You can build your app from your own Dockerfile, or you can run an existing container image from Docker Hub or a private registry. A model that you packaged with Cog is a container image, so it can run on fal. This guide shows three migration paths for a Cog model:
  1. Run the existing Cog image without code changes.
  2. Build from a Dockerfile, such as the Dockerfile that Cog generates.
  3. Convert the Cog Predictor class to a fal.App.
Each path deploys with the fal CLI and gives you autoscaling, logs, and app analytics. For other Docker servers that do not use Cog, see Migrate an External Docker Server.

Choose a Migration Path

The time includes the first image build and a test deployment. Large model weights add download time to the first build and the first runner start.

Before You Start

  1. Install the fal CLI and log in. See Installation.
  2. Make sure your account has Serverless access. Request access on the Serverless get-started page.
  3. Choose a GPU. See Machine Types for the list, for example GPU-H100 or GPU-B200.

Path 1: Run the Existing Cog Image

A Cog image contains its own HTTP server. On fal, an image-only app starts the container and sends requests to the port that you expose. You do not write a fal.App class.

Build and Push the Image

Build the image with Cog and push it to a registry that fal can pull from:
If the registry is private, configure credentials. See Private Docker Registries for Docker Hub, Google Artifact Registry, Amazon ECR, and Azure Container Registry.

Configure the App

Add the app to pyproject.toml. Do not set ref or python_entry_point. Without them, fal treats the container as an image-only app and does not load the fal Python runtime.
The Cog image already defines the command that starts its server, so you do not set cmd. To override it, add cmd under [tool.fal.apps.my-cog-model.image]. See the pyproject.toml reference.

Test and Deploy

Run an ephemeral deployment to test the image:
fal run ignores the auth value in pyproject.toml and defaults to public. Pass --auth private unless you want the test deployment to be public. fal deploy uses the configured value.
Deploy the app to a persistent URL:

Call the App

fal forwards each request to the container without changes. The Cog API stays the same, so send the Cog request body to the /predictions path under your endpoint ID:
The queue returns a status_url and a response_url. Poll the status URL, then fetch the result from the response URL. See Calling Your Endpoints for queue, webhook, and streaming flows. The Cog server returns files in the format that Cog uses, such as data URIs or paths. They do not go to the fal CDN. To return CDN URLs, use path 3.

Path 2: Build From a Dockerfile

Use this path when the model needs system packages, a specific CUDA version, or build steps that a requirements list cannot express. fal builds the image from your Dockerfile and caches the result.

Get a Dockerfile

If you already have a Dockerfile, use it. If you only have a cog.yaml, print the Dockerfile that Cog generates:
Then edit the generated Dockerfile:
  1. Remove the COPY . /src, EXPOSE, and CMD lines at the end. fal starts the app.
  2. Remove the Cog wheel installation (cog-*.whl). fal does not use the Cog runtime.
  3. Replace the Cog requirements step with your pip packages.
  4. Make sure that curl is installed. fal uses it when a runner starts.
  5. Install fal as the last step. This gives compatible versions of pydantic, protobuf, and boto3.
cog debug is a hidden debugging command, and Cog does not guarantee its output format. The generated Dockerfile can change between Cog versions.

Reference the Dockerfile From a fal.App

ContainerImage.from_dockerfile() reads a file from disk. To keep the Dockerfile in your Python file, use ContainerImage.from_dockerfile_str(). Both accept build_args, secrets, registries, and a build context_dir for COPY. See Use a Custom Container Image for all options and the build cache rules. You can also keep the Dockerfile and its settings in pyproject.toml. Set dockerfile = "Dockerfile" under [tool.fal.apps.<app-name>.image]. See the pyproject.toml reference.

Path 3: Convert the Predictor to a fal.App

The Cog Predictor class maps directly to a fal.App. The setup() method stays the same. The predict() method becomes an @fal.endpoint method with Pydantic input and output models.
In the fal version, class attributes replace cog.yaml. fal.toolkit.Image replaces cog.Path and uploads the image to the fal CDN, so the response contains a URL. The imports are inside setup() so that they run on the runner, not on your machine. See Serialization and Build for the reason. Test the app on a temporary runner, then deploy it:
fal run executes setup() and your endpoints as production does. Import errors and model-load failures show in your terminal, not as a failed production deployment. Call the deployed app:

What Changes After the Migration

How Billing Works on fal

fal bills Serverless apps per second of runner time, at the rate for the machine type. A runner is a container on a GPU. You pay while a runner is alive, not per prediction. fal does not charge for requests that fail with an HTTP 5xx status. fal bills a multi-GPU runner as the GPU count multiplied by the duration. See Serverless Pricing for the full rules, and fal.ai/pricing for the hourly rate of each GPU. Three settings decide most of the cost:
  • keep_alive keeps an idle runner warm for a number of seconds after the last request. A longer value reduces cold starts and adds IDLE time.
  • min_concurrency keeps a minimum number of runners alive at all times. Set it to 0 to scale to zero, so that an app with no traffic has no compute charge.
  • machine_type sets the per-second rate. Use the smallest GPU that fits the model.
To estimate the cost, add up the seconds that your runners are alive, not the number of predictions. App Analytics shows runner time and cost for each app.

Test Your Deployment

Open your app from the Apps dashboard. Follow Testing Your Own Apps to test an endpoint. Use the app’s Logs and Requests pages to inspect recorded requests.

Next Steps