Nano Banana 2 Lite vs 2.1 vs Pro: Google Flow Image Models Compared

7 min read • July 2, 2026 (October 20, 2026)

Table of contents

  1. Introduction
  2. What are the three Nano Banana models?
    1. Upscaling to 2K/4K
  3. Pricing
  4. The comparison prompt
  5. Generate across all three models
  6. Examples
  7. Which Nano Banana model should you use?
  8. Run it yourself
  9. Frequently asked questions
  10. Conclusion

Introduction

Google Flow ships three Nano Banana image models, nano-banana-2-lite, nano-banana-2 and nano-banana-pro, and the useapi.net Google Flow API runs all three from one prompt with your Google Flow account. Images are included on every Google AI subscription, a free account too, where the official Gemini API charges $0.034 to $0.134 per image (as of October 2026). There’s no Google Cloud project and no API key.

This guide runs the exact same prompt through Lite, 2.1, and Pro so you can see how they differ, then hands you a runnable Node.js script that generates the whole set in one command. Want a from-scratch how-to first? See the sibling image-generation tutorial.

What are the three Nano Banana models?

Pick a model per request with the model field. If you omit it, Google Flow uses nano-banana-2-lite — its default since July 2026. All three run on any Google AI subscription, including a free account.

Model id Marketing name Best for References (I2I) Speed
nano-banana-2-lite (default) Nano Banana 2 Lite / Gemini 3.1 Flash-Lite Image fast, high-volume images on any plan max 10 fastest
nano-banana-2 Nano Banana 2.1 balanced quality and speed max 10 fast
nano-banana-pro Nano Banana Pro / Gemini 3 Pro Image highest fidelity and instruction-following max 10 slower

All three accept the same aspect ratios (16:9, 4:3, 1:1, 3:4, 9:16, plus auto in image-to-image mode), count (1–4), seed for reproducibility, up to 10 reference images, inline @-mentions, and 2K/4K upscaling. The deprecated aliases imagen-4 (Google removed Imagen from Flow in July 2026) and nano-banana are still accepted and map to nano-banana-2-lite and nano-banana-2 respectively. Full per-model detail is on the POST /images reference.

Upscaling to 2K/4K

Any generated image can be upscaled with POST /images/upscale: pass its mediaGenerationId and a resolution of 2k (default) or 4k. The response is base64 in encodedImage. 2k works on any plan, and 4k needs Google AI Ultra.

Pricing

Images cost no Flow credits on any Google AI subscription, a free account included, and useapi.net adds no per-image charge. The price of every model on every plan, against the official API, is in the Google Flow price table. See the setup guide to connect your account.

The comparison prompt

A model comparison is only useful if the prompt is hard. This one is a deliberately absurd, single-frame scene that stress-tests several things at once: a named photographic style (David LaChapelle), a multi-subject spatial layout (a swarm forming an arrow in the top-left, a forced-perspective bee in the bottom-right), prop fidelity (dripping honeycomb), a specific comedic facial expression (o_O cartoon eyes), and a clashing tone — all in one cohesive image.

A visually breathtaking, beautifully absurd, single-frame photograph in the hyper-saturated,
glossy, surreal-comedy editorial style of David LaChapelle, shot at a sun-dappled backyard
apiary at golden hour on an 85mm f/1.4 lens with creamy shallow depth of field. In the center
midground, a gorgeous, radiant young woman beekeeper with an elegant figure, flawless glowing
sun-kissed skin and a warm playful smile, incongruously wearing a tiny mini bikini and a
beekeeper's veil hat pushed back off her face, stands among the wooden hive boxes on the grass and lifts a single
open beehive frame heavy with golden honeycomb, thick honey oozing and stringing down in glossy
ribbons and catching the light. She looks directly into the camera, delighted and completely
unbothered by the bees swirling around her. In the top-left of the frame, a dense swarm of bees
bunches together and organizes into a bold, unmistakable arrow / pointer shape aimed straight at
her, as if frantically calling everyone's attention. In the extreme bottom-right foreground of
the exact same scene, photobombing the lens, is a huge forced-perspective close-up of a single
frazzled worker bee, staring directly into the camera with bulging, mind-blown "o_O" cartoon
googly eyes, completely frozen in comical disbelief. Single cohesive image, seamless depth of
field, no cut-ins, warm dynamic backlighting, glistening honey highlights, crazy situational
comedy, hyper-detailed, masterpiece.

Generate across all three models

You need a useapi.net API token and a connected Google Flow account. POST /images is synchronous — one call blocks until the images are ready (typically 20–60 seconds, and the Pro model can take up to ~2 minutes under load) and returns a media[] array with one entry per image, so there’s no jobid to poll.

A single call — swap model to compare:

curl -X POST "https://api.useapi.net/v1/google-flow/images" \
  -H "Authorization: Bearer $USEAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana-pro",
    "aspectRatio": "9:16",
    "count": 4,
    "prompt": "A beekeeper at golden hour lifting a dripping honeycomb frame, a swarm forming an arrow in the sky, a forced-perspective bee with o_O googly eyes in the foreground"
  }' > result.json

# each image is at .media[N].image.generatedImage.fifeUrl
curl -o pro_1.jpg "$(jq -r '.media[0].image.generatedImage.fifeUrl' result.json)"

To run the full comparison in one command, the Node.js script below reads prompts.json — one entry per model, all with the same prompt — submits each, and saves every returned image with a model-labeled filename, downloading it from fifeUrl or decoding the inline encodedImage when the URL is missing. A failed image is logged and the run moves on. You need Node.js v21+. Put both files in a folder and run node ./google-flow-nano-banana-compare.mjs API_TOKEN EMAIL, where API_TOKEN is your useapi.net API token and EMAIL is your connected Google Flow account. The script looks the account up by email and checks its health before submitting, and sends no captchaToken — the useapi.net worker solves the reCAPTCHA automatically.

Prefer to clone and run it? The complete script, a Python port, and prompts.json are on GitHub in useapi/google-flow-api.

Expand prompts.json
[
    {
        "model": "nano-banana-2-lite",
        "aspectRatio": "9:16",
        "count": 4,
        "prompt": "A beekeeper at golden hour lifting a dripping honeycomb frame in the surreal editorial style of David LaChapelle, a dense bee swarm forming a bold arrow in the top-left, a forced-perspective bee with o_O cartoon googly eyes photobombing the bottom-right. Single cohesive image, masterpiece."
    },
    {
        "model": "nano-banana-2",
        "aspectRatio": "9:16",
        "count": 4,
        "prompt": "A beekeeper at golden hour lifting a dripping honeycomb frame in the surreal editorial style of David LaChapelle, a dense bee swarm forming a bold arrow in the top-left, a forced-perspective bee with o_O cartoon googly eyes photobombing the bottom-right. Single cohesive image, masterpiece."
    },
    {
        "model": "nano-banana-pro",
        "aspectRatio": "9:16",
        "count": 4,
        "prompt": "A beekeeper at golden hour lifting a dripping honeycomb frame in the surreal editorial style of David LaChapelle, a dense bee swarm forming a bold arrow in the top-left, a forced-perspective bee with o_O cartoon googly eyes photobombing the bottom-right. Single cohesive image, masterpiece."
    }
]
Expand google-flow-nano-banana-compare.mjs script
/*

Script version 1.1, September 11, 2026

Batch-compare Google Flow's Nano Banana image models (2 Lite, 2.1, Pro) with the useapi.net API 🚀
Reads prompts.json (one entry per model), submits each to the synchronous POST /images endpoint,
and downloads every returned image with a model-labeled filename.
For more details visit https://useapi.net/docs/api-google-flow-v1/post-google-flow-images

Companion tutorial:
  https://useapi.net/docs/articles/google-flow-nano-banana-compare

Installation Instructions:
==========================

You need Node.js v21 or newer installed to run this script. Download and install Node.js from:

- Windows, macOS, Linux: https://nodejs.org/

After installation, verify by running the following command in a terminal:

   node -v

Running the Script:
===================

Usage: node google-flow-nano-banana-compare.mjs <API_TOKEN> <EMAIL> [PROMPTS_FILE]

Replace API_TOKEN with your actual useapi.net API token, see https://useapi.net/docs/start-here/setup-useapi
Replace EMAIL with configured Google Flow email account, see https://useapi.net/docs/start-here/setup-google-flow
If optional PROMPTS_FILE not provided prompts.json will be used.

Example:
--------

node google-flow-nano-banana-compare.mjs user:1234-abcdefhijklmnopqrstuv [email protected]

Changelog:
==========

- July 2, 2026: Initial release.
- September 11, 2026: Saves encodedImage when fifeUrl is absent, and writes a downloaded image only once it has been fully received, so a failed download leaves no partial file for the next run to skip as "already exists".

*/

import fs from 'fs/promises';
import { writeFile } from 'node:fs/promises';

// Constants
const DEFAULT_PROMPTS_FILE = 'prompts.json';
const DEFAULT_MODEL = 'nano-banana-2-lite';
const SLEEP_RETRY = 30 * 1000; // in milliseconds

const urlAccounts = 'https://api.useapi.net/v1/google-flow/accounts';
const urlImages = 'https://api.useapi.net/v1/google-flow/images';

// Utility to sleep for given milliseconds
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const elapsedTimeSec = (start) => (Date.now() - start) / 1000;

// Function to fetch configured Google Flow API accounts
async function fetchAccounts(apiToken) {
    const response = await fetch(urlAccounts, {
        headers: {
            'Accept': 'application/json',
            'Authorization': `Bearer ${apiToken}`
        }
    });

    if (!response.ok) {
        console.error(`⛔ Error fetching accounts (HTTP ${response.status}): ${response.statusText}`);
        process.exit(1);
    }

    return response.json();
}

// Save a single image from its signed fifeUrl. fifeUrl is normally present; when it is absent
// the image arrived inline as base64 in encodedImage. A failure is reported and skipped.
async function downloadImage(img, filename) {
    try {
        await fs.access(filename);
        console.log(`⚠️ ${filename} already exists. Skipping download.`);
        return;
    } catch {
        // File does not exist, proceed with downloading
    }

    const url = img?.fifeUrl;

    if (!url && img?.encodedImage) {
        console.log(`✅ Saving ${filename} from encodedImage`);
        try {
            await writeFile(filename, Buffer.from(img.encodedImage, 'base64'));
        } catch (err) {
            console.error(`⛔ Unable to save ${filename}: ${err}`);
        }
        return;
    }

    if (!url) {
        console.error(`🛑 No fifeUrl or encodedImage for ${filename}`);
        return;
    }

    console.log(`✅ Downloading ${filename}`);
    try {
        const imageResponse = await fetch(url);
        if (!imageResponse.ok) {
            console.error(`⛔ Unable to download ${filename} (HTTP ${imageResponse.status})`);
            return;
        }
        // Read the whole body before creating the file, so a failed download leaves no
        // partial file behind for the next run to skip as "already exists".
        const data = Buffer.from(await imageResponse.arrayBuffer());
        await writeFile(filename, data);
    } catch (err) {
        console.error(`⛔ Error during download: ${err}`);
    }
}

// Submit a single prompt to the synchronous POST /images endpoint and download the results.
async function submitImage(apiToken, email, prompt, index) {
    const model = prompt.model ?? DEFAULT_MODEL;

    // Build the request body.
    const body = { model, email, prompt: prompt.prompt };
    for (const key of ['aspectRatio', 'count', 'seed'])
        if (prompt[key] !== undefined) body[key] = prompt[key];

    console.log(`🚀 ${model} » Prompt #${index} • account ${email} …`);
    const startTime = Date.now();

    while (true) {
        const response = await fetch(urlImages, {
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${apiToken}`
            },
            body: JSON.stringify(body)
        });

        const responseText = await response.text();

        if (response.status == 200) {
            const media = JSON.parse(responseText)?.media ?? [];

            if (media.length == 0)
                console.error(`🛑 200 OK but no media (moderated?) for ${model}`);

            // count > 1 returns multiple images in the media array.
            for (let i = 0; i < media.length; i++) {
                const img = media[i]?.image?.generatedImage;
                await downloadImage(img, `${model}_${i + 1}.jpg`);
            }
            console.log(`🆗 ${model} done (${elapsedTimeSec(startTime)} sec)`);
            return 200;
        }

        switch (response.status) {
            case 429:
            case 503:
                console.log(`🔄️ Retry on HTTP ${response.status}`, responseText);
                await sleep(SLEEP_RETRY);
                break;
            default:
                console.error(`🛑 ${model} failed with HTTP ${response.status}`, responseText);
                return response.status;
        }
    }
}

// Main function
async function main() {
    const apiToken = process.argv[2];
    const email = process.argv[3];
    const promptFile = process.argv[4] || DEFAULT_PROMPTS_FILE;

    if (!apiToken || !email) {
        console.error('Usage: node google-flow-nano-banana-compare.mjs <API_TOKEN> <EMAIL> [PROMPTS_FILE]');
        process.exit(1);
    }

    console.info('Script v1.1 • Node version ' + process.version);

    const accounts = await fetchAccounts(apiToken);

    if (!accounts[email]) {
        console.error(`⛔ Account ${email} not found. Please refer to https://useapi.net/docs/start-here/setup-google-flow`);
        process.exit(1);
    }

    if (accounts[email].health && accounts[email].health !== 'OK') {
        console.error(`⛔ Account ${email} health is '${accounts[email].health}'. Please resolve and update the account, see https://useapi.net/docs/start-here/setup-google-flow`);
        process.exit(1);
    }

    const prompts = JSON.parse(await fs.readFile(promptFile, 'utf8'));
    console.log(`Comparing ${prompts.length} model runs …`);

    const start = new Date();
    for (let i = 0; i < prompts.length; i++)
        await submitImage(apiToken, email, prompts[i], i + 1);

    console.info('COMPLETED', new Date(), '• elapsed', elapsedTimeSec(start), 'sec');
}

main();

Examples

Here is the same beekeeper prompt rendered by each model at 9:16, generated through this Google Flow API. The differences are consistent: Pro is the most polished and the most literal about the instructions, 2.1 is the most dynamic, and Lite is the fastest while staying close.

nano-banana-pro — the most polished and editorial, and the only model that reliably renders the veil netting, the bees crawling on the comb, and the literal o_O cartoon eyes.

Nano Banana Pro beekeeper result via the Google Flow API

nano-banana-2 — the most dynamic and energetic interpretation, with the clearest arrow-shaped swarm and lots of situational detail (work boots, bees on the frame).

nano-banana-2 beekeeper result via the Google Flow API

nano-banana-2-lite — the fastest of the three (roughly half Pro’s time in our runs) while keeping the composition, the honey drip, and the googly-eyed foreground bee.

Nano Banana 2 Lite beekeeper result via the Google Flow API

Which Nano Banana model should you use?

  • Reach for nano-banana-pro when fidelity matters most — hero shots, complex multi-subject scenes, precise text or instruction-following. It is the slowest of the three.
  • Reach for nano-banana-2 for a strong balance of quality and speed, or when you want a more dynamic, stylized read of a prompt.
  • Reach for nano-banana-2-lite (the default) for iteration and high-volume batches where speed matters and the quality is still very close.

Because they share the same request shape, switching is a one-word change to model — generate a batch across all three and pick the winner, exactly like the script above does.

Run it yourself

The complete Node.js script, a Python port, and prompts.json live in useapi/google-flow-api/nano-banana-compare. Clone it, edit prompts.json, and run one command to generate the full comparison set with your Google Flow account.

Frequently asked questions

  • Is there a Nano Banana 2.1 or Nano Banana Pro API? Through useapi.net, yes: the Google Flow API runs Google Flow’s versions as nano-banana-2 (Nano Banana 2.1), nano-banana-2-lite and nano-banana-pro on POST /images. Google has published no API rate for Nano Banana 2.1, and Nano Banana Pro costs $0.134 an image on the official Gemini API, against no per-image charge here (as of October 2026).
  • What is the difference between Nano Banana 2 Lite, 2.1, and Pro? Through useapi.net all three run on the same endpoint, each with its own strength. nano-banana-pro (Gemini 3 Pro Image) is the most polished and follows instructions most closely, nano-banana-2 (Nano Banana 2.1) gives the most dynamic read, and nano-banana-2-lite (Gemini 3.1 Flash-Lite Image), the default, took about half Pro’s time in our runs. See Which model should you use?
  • How much does the Nano Banana API cost? Through useapi.net, images cost no Flow credits on any Google AI subscription, a free account included, and there is no Gemini API key or Cloud billing account to set up. On the official Gemini API, Nano Banana 2 Lite costs about $0.034 per 1K image (as of October 2026). See Pricing.
  • Do images get moderated? Through useapi.net, your prompts reach Google’s own content moderation, and a rejected request returns an empty result. Moderation decisions vary between requests and between models, so retrying, editing the prompt or switching models often succeeds, because each Nano Banana model moderates a little differently.
  • Do I need a captcha or a Google Cloud project? Through useapi.net you need neither a Google Cloud project nor a captcha of your own. Google Flow asks for a reCAPTCHA on every image, and the useapi.net worker solves it automatically: your first Google Flow account comes with 300 free solves on our own AntiCaptcha, CapSolver and EzCaptcha keys, and after that you add your own provider keys. The script here sends no captchaToken.

Conclusion

Visit our Discord Server or Telegram Channel for any support questions and concerns.

Check our GitHub repo with code examples.

Cross posted

Also published on dev.to and discussed on Reddit.