Skip to main content

FAL Provider

FAL provides ultra-fast inference for image and video generation models. Known for speed optimization and support for latest models including FLUX, Stable Diffusion, and video generation.

Setup​

Installation​

import (
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/fal"
)

Configuration​

provider := fal.New(fal.Config{
APIKey: os.Getenv("FAL_API_KEY"),
Headers: map[string]string{"X-Custom": "value"},
})

model, err := provider.ImageModel("fal-ai/flux-pro")

fal.Config.APIKey falls back to the FAL_API_KEY environment variable, then to FAL_KEY, if left empty. fal.Config.Headers are sent on every request across image, video, speech, and transcription models.

Breaking change: the default base URL is now https://fal.run (was https://fal.run/fal-ai, which doubled the path for fully-qualified model IDs and broke default-config requests). Always pass fully-qualified model IDs like fal-ai/fast-sdxl, not fast-sdxl. The image and video default models are fal-ai/fast-sdxl and fal-ai/luma-ray.

Get API Key​

export FAL_API_KEY=...

Available Models​

Image Generation​

Model IDQualitySpeedPriceBest For
fal-ai/flux-proExcellentFast$0.05/imageHigh quality
fal-ai/flux-schnellGoodVery Fast$0.003/imageSpeed
fal-ai/stable-diffusion-xlHighFast$0.03/imageGeneral

Video Generation​

Model IDQualitySpeedPriceBest For
fal-ai/stable-video-diffusionMediumMedium$0.10/videoVideo from image
fal-ai/runway-gen3HighSlow$0.50/videoHigh quality video

Provider-Specific Features​

Ultra-Fast Inference​

FAL optimizes for speed:

start := time.Now()
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: model,
Prompt: "A sunset over mountains",
})
elapsed := time.Since(start)
fmt.Printf("Generated in %v\n", elapsed) // ~1-2 seconds

Video Generation​

Create videos from text or images:

videoModel, err := provider.VideoModel("fal-ai/stable-video-diffusion")

// Generate from image
initImage, _ := os.ReadFile("frame.png")

fps := 10
result, err := ai.GenerateVideo(ctx, ai.GenerateVideoOptions{
Model: videoModel,
Prompt: ai.VideoPrompt{
Image: &ai.VideoPromptImage{Data: initImage},
},
FPS: &fps,
ProviderOptions: map[string]interface{}{
"fal": map[string]interface{}{
"frames": 25,
},
},
})

os.WriteFile("output.mp4", result.Video.Data, 0644)

Async Video And Webhooks​

fal.VideoModel implements provider.VideoModelStarter / VideoModelStatusChecker, so it also works with ai.ExperimentalStartVideo / ai.ExperimentalGetVideoStatus, and can complete via a webhook instead of polling:

started, err := ai.ExperimentalStartVideo(ctx, ai.StartVideoOptions{
Model: videoModel,
Prompt: ai.VideoPrompt{Text: "A cat playing piano"},
WebhookURL: "https://example.com/fal-webhook",
})

Speech and Transcription​

speechModel, err := provider.SpeechModel("fal-ai/minimax/speech-02-hd")
if err != nil {
log.Fatal(err)
}

result, err := ai.GenerateSpeech(ctx, ai.GenerateSpeechOptions{
Model: speechModel,
Text: "Hello from Fal.",
})
transcriptionModel, err := provider.TranscriptionModel("fal-ai/wizper")
if err != nil {
log.Fatal(err)
}

transcript, err := ai.Transcribe(ctx, ai.TranscribeOptions{
Model: transcriptionModel,
Audio: audioBytes,
})

Fal does not support reranking — provider.RerankingModel returns an error.

Examples​

Basic Image Generation​

package main

import (
"context"
"fmt"
"log"
"os"
"time"

"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/fal"
)

func main() {
provider := fal.New(fal.Config{
APIKey: os.Getenv("FAL_KEY"),
})

model, err := provider.ImageModel("fal-ai/flux-schnell")
if err != nil {
log.Fatal(err)
}

start := time.Now()
result, err := ai.GenerateImage(context.Background(), ai.GenerateImageOptions{
Model: model,
Prompt: "A peaceful zen garden",
})
if err != nil {
log.Fatal(err)
}

fmt.Printf("Generated in %v\n", time.Since(start))
os.WriteFile("garden.png", result.Images[0].Data, 0644)
}

Fast Batch Generation​

prompts := []string{
"A red apple",
"A green apple",
"A yellow apple",
}

// Parallel generation
var wg sync.WaitGroup
for i, prompt := range prompts {
wg.Add(1)
go func(idx int, p string) {
defer wg.Done()

result, err := ai.GenerateImage(context.Background(), ai.GenerateImageOptions{
Model: model,
Prompt: p,
})
if err != nil {
return
}

filename := fmt.Sprintf("apple_%d.png", idx)
os.WriteFile(filename, result.Images[0].Data, 0644)
}(i, prompt)
}
wg.Wait()

Best Practices​

  1. Speed Optimization

    • Use flux-schnell for rapid iteration
    • Parallel requests for batches
    • Leverage fast inference for real-time apps
  2. Quality vs Speed

    • Use schnell for previews
    • Use pro for finals
    • Balance based on use case
  3. Cost Management

    • Schnell is very cost-effective
    • Cache results
    • Use for high-volume applications

Rate Limits & Pricing​

Check dashboard for current limits and pricing.

Workflow Serialization​

Fal image, speech, and transcription models can cross a workflow boundary with provider.SerializeImageModel / DeserializeImageModel, provider.SerializeSpeechModel / DeserializeSpeechModel, and provider.SerializeTranscriptionModel / DeserializeTranscriptionModel. See Provider Serialization for the mechanism; video models are not yet serializable.

See Also​