---
title: "Go Image Generation API: Complete Guide"
description: "Generate images from Go with an image API. HTTP client setup, JSON payloads, error handling, and concurrent generation. Production-ready examples included."
url: "https://www.imejis.io/blogs/tutorials/golang-image-generation-api"
published: "2026-03-28"
---

# Go Image Generation API: Complete Guide

No image generation API has published a Go integration guide. Not Bannerbear, not Placid, not anyone. If you've been searching for "golang image generation API," you probably found nothing useful. We have guides for [Node.js](/blogs/node-js-integration), [Python](/blogs/tutorials/python-image-api-integration), and [PHP/Laravel](/blogs/tutorials/php-image-generation-laravel) too, but this one is all Go.

That changes now. Go's [standard library](https://pkg.go.dev/std) makes this almost embarrassingly simple. No SDKs to install, no dependencies to manage. Just `net/http`, a JSON payload, and you're generating images. Here's the complete guide with production-ready code. All pricing as of March 2026.

## Basic Image Generation in Go

Here's the simplest working example. I've stripped it down to the essentials:

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	templateID := "YOUR_TEMPLATE_ID"
	apiKey := os.Getenv("IMEJIS_API_KEY")

	// Build the JSON payload
	payload := map[string]any{
		"headline": map[string]any{
			"text": "Hello from Go!",
		},
		"subtitle": map[string]any{
			"text": "Generated with net/http",
		},
	}

	body, _ := json.Marshal(payload)

	// Make the API call
	url := fmt.Sprintf("https://render.imejis.io/v1/%s", templateID)
	req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
	req.Header.Set("dma-api-key", apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	// Save the image
	imageData, _ := io.ReadAll(resp.Body)
	os.WriteFile("output.png", imageData, 0644)
	fmt.Println("Image saved to output.png")
}
```

Run it: `IMEJIS_API_KEY=your-key go run main.go`

That's it. No external packages. The API returns the image binary directly, so you just write it to a file.

## Production-Ready Client

The basic example works, but production code needs proper error handling, timeouts, and reusable structure. Here's what I use in real projects:

```go
package imejis

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

// Client handles image generation API calls.
type Client struct {
	apiKey     string
	baseURL    string
	httpClient *http.Client
}

// NewClient creates a configured API client.
func NewClient(apiKey string) *Client {
	return &Client{
		apiKey:  apiKey,
		baseURL: "https://render.imejis.io/v1",
		httpClient: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

// Generate renders an image from a template with the given data.
func (c *Client) Generate(ctx context.Context, templateID string, data map[string]any) ([]byte, error) {
	body, err := json.Marshal(data)
	if err != nil {
		return nil, fmt.Errorf("marshal payload: %w", err)
	}

	url := fmt.Sprintf("%s/%s", c.baseURL, templateID)
	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(body))
	if err != nil {
		return nil, fmt.Errorf("create request: %w", err)
	}

	req.Header.Set("dma-api-key", c.apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("api request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		errBody, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("api error %d: %s", resp.StatusCode, string(errBody))
	}

	return io.ReadAll(resp.Body)
}
```

### Using the Client

```go
package main

import (
	"context"
	"fmt"
	"os"
	"your-module/imejis"
)

func main() {
	client := imejis.NewClient(os.Getenv("IMEJIS_API_KEY"))

	imageData, err := client.Generate(
		context.Background(),
		"YOUR_TEMPLATE_ID",
		map[string]any{
			"headline":      map[string]any{"text": "Summer Sale"},
			"price":         map[string]any{"text": "$29.99"},
			"product_image": map[string]any{"image": "https://example.com/product.jpg"},
		},
	)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Generation failed: %v\n", err)
		os.Exit(1)
	}

	os.WriteFile("output.png", imageData, 0644)
	fmt.Println("Done!")
}
```

Clean, testable, and handles errors properly. The `context.Context` parameter lets you cancel long-running requests or set deadlines.

## Typed Payloads with Structs

If you're generating the same template repeatedly, define a struct instead of using `map[string]any`:

```go
type ProductCard struct {
	Headline     TextField `json:"headline"`
	Price        TextField `json:"price"`
	ProductImage ImageField `json:"product_image"`
	Badge        TextField `json:"discount_badge,omitempty"`
}

type TextField struct {
	Text  string `json:"text"`
	Color string `json:"color,omitempty"`
}

type ImageField struct {
	Image string `json:"image"`
}
```

Now your generation calls are type-safe:

```go
card := ProductCard{
	Headline:     TextField{Text: "Classic Runner"},
	Price:        TextField{Text: "$29.99"},
	ProductImage: ImageField{Image: "https://example.com/runner.jpg"},
	Badge:        TextField{Text: "40% OFF"},
}

// Marshal card to JSON and pass to client.Generate()
```

The compiler catches typos. Your IDE gives you autocomplete. And `omitempty` on optional fields means they're excluded from the JSON when empty.

## Concurrent Generation with Goroutines

This is where Go really shines. Generating 100 images sequentially takes about 3 minutes. With goroutines, you can cut that to under 30 seconds.

```go
package main

import (
	"context"
	"fmt"
	"os"
	"sync"
	"your-module/imejis"
)

type Product struct {
	ID    string
	Name  string
	Price string
	Image string
}

func main() {
	client := imejis.NewClient(os.Getenv("IMEJIS_API_KEY"))
	templateID := "YOUR_TEMPLATE_ID"

	products := []Product{
		{ID: "1", Name: "Classic Runner", Price: "$29.99", Image: "https://example.com/runner.jpg"},
		{ID: "2", Name: "Urban Jacket", Price: "$89.00", Image: "https://example.com/jacket.jpg"},
		// ... hundreds more
	}

	// Limit concurrency to 5 simultaneous requests
	sem := make(chan struct{}, 5)
	var wg sync.WaitGroup

	for _, p := range products {
		wg.Add(1)
		sem <- struct{}{} // acquire semaphore

		go func(product Product) {
			defer wg.Done()
			defer func() { <-sem }() // release semaphore

			data := map[string]any{
				"product_name":  map[string]any{"text": product.Name},
				"price":         map[string]any{"text": product.Price},
				"product_image": map[string]any{"image": product.Image},
			}

			imageData, err := client.Generate(context.Background(), templateID, data)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Failed %s: %v\n", product.ID, err)
				return
			}

			os.WriteFile(fmt.Sprintf("output/%s.png", product.ID), imageData, 0644)
			fmt.Printf("Generated: %s\n", product.Name)
		}(p)
	}

	wg.Wait()
	fmt.Println("All done!")
}
```

The semaphore channel limits concurrency to 5 simultaneous requests. This keeps you under rate limits while still being 5x faster than sequential generation. I've used this pattern to generate 2,000 product images in about 12 minutes. For more on managing rate limits and caching at scale, see [image API rate limits and caching](/blogs/tutorials/image-api-rate-limits-caching).

## HTTP Handler: Generate Images on Request

If you're building a web service that generates images on the fly:

```go
func handleGenerate(client *imejis.Client) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		title := r.URL.Query().Get("title")
		if title == "" {
			http.Error(w, "title parameter required", http.StatusBadRequest)
			return
		}

		imageData, err := client.Generate(r.Context(), "YOUR_TEMPLATE_ID", map[string]any{
			"headline": map[string]any{"text": title},
		})
		if err != nil {
			http.Error(w, "generation failed", http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "image/png")
		w.Header().Set("Cache-Control", "public, max-age=86400")
		w.Write(imageData)
	}
}
```

Now `GET /generate?title=Hello+World` returns a PNG image. Useful for dynamic OG images, email headers, or any endpoint that needs to serve generated images.

## Common Patterns

### Retry with Backoff

```go
func (c *Client) GenerateWithRetry(ctx context.Context, templateID string, data map[string]any) ([]byte, error) {
	var lastErr error
	for attempt := 0; attempt < 3; attempt++ {
		result, err := c.Generate(ctx, templateID, data)
		if err == nil {
			return result, nil
		}
		lastErr = err
		time.Sleep(time.Duration(attempt+1) * time.Second)
	}
	return nil, fmt.Errorf("failed after 3 attempts: %w", lastErr)
}
```

### Upload to S3

```go
func uploadToS3(bucket, key string, data []byte) error {
	cfg, _ := config.LoadDefaultConfig(context.Background())
	client := s3.NewFromConfig(cfg)

	_, err := client.PutObject(context.Background(), &s3.PutObjectInput{
		Bucket:      &bucket,
		Key:         &key,
		Body:        bytes.NewReader(data),
		ContentType: aws.String("image/png"),
	})
	return err
}
```

## Why Go Works Well for Image Generation

I've written image generation code in Node.js, Python, and Go. Go has some real advantages for this use case:

- **Goroutines for concurrency**: 5 lines of code to parallelize 1,000 image generations. Try doing that in Python without asyncio headaches.
- **No dependencies needed**: The standard library handles HTTP, JSON, file I/O. Your `go.mod` stays clean.
- **Fast startup**: No runtime warmup. Great for serverless functions or CLI tools.
- **Type safety with structs**: Catch template field typos at compile time, not at runtime.
- **Single binary deployment**: `go build` and deploy one file. No `node_modules`, no virtualenvs.

The only downside? No official SDK from any image API provider. But as you've seen, you don't need one. Go's standard library is the SDK.

## Getting Started

1. **[Sign up for Imejis.io](https://app.imejis.io)**: 100 free images per month
2. **Create a template** in the visual editor
3. **Copy the basic example** from this guide
4. **Set your API key**: `export IMEJIS_API_KEY=your-key`
5. **Run**: `go run main.go`

First image in under 5 minutes. No dependencies to install. If you're new to image APIs in general, our [beginner guide to generating images with an API](/blogs/tutorials/how-to-generate-images-with-api) covers the fundamentals.

For the JSON payload format, see our [Generate Images from JSON](/blogs/tutorials/generate-images-from-json) guide. For bulk generation, check [Batch Image Generation from CSV](/blogs/tutorials/batch-image-generation-csv). And for API pricing, see our [Image Generation API Pricing Comparison](/blogs/comparisons/image-generation-api-pricing-comparison).

## FAQ

### Can I generate images from a Go application?

Yes. Use Go's standard [net/http](https://pkg.go.dev/net/http) package to call the API. Send a POST with JSON, get image bytes back. No external libraries needed.

### Do I need an SDK for Go image generation?

No. Go's standard library handles HTTP and JSON natively. The code in this guide uses only `net/http`, `encoding/json`, and `os`. Zero third-party dependencies.

### How fast is image generation from Go?

The API call takes under 2 seconds. Go's goroutines make concurrent generation trivial. With 5 goroutines, you can generate about 150 images per minute.

### What image formats does the API return?

[Imejis.io](https://www.imejis.io) returns PNG by default. The response body is raw image bytes that you write to a file, upload to S3, or serve over HTTP.

### How much does image generation cost from Go?

Same as any language. [Imejis.io](https://www.imejis.io/pricing) starts at $14.99/month for 1,000 images, with a free tier of 100/month. The API doesn't charge differently based on which language calls it.

## Go Generate Some Images

Go's strength is doing simple things fast with minimal dependencies. Image generation via API fits that perfectly. [Try Imejis.io free](https://app.imejis.io) and generate your first image from Go in about 5 minutes.
