nano-banana
Nano Banana Skill
Python scripting with Gemini image generation using uv. Write small, focused scripts using heredocs for quick tasks—no files needed for one-off operations.
Choosing Your Approach
Quick image generation: Use heredoc with inline Python for one-off image requests.
Complex workflows: When multiple steps are needed (generate -> refine -> save), break into separate scripts and iterate.
Scripting tasks: For non-image Python tasks, use the same heredoc pattern with uv run.
Writing Scripts
Execute Python inline using heredocs with inline script metadata for dependencies:
uv run - << 'EOF'
# /// script
# dependencies = ["google-genai", "pillow"]
# ///
from google import genai
from google.genai import types
client = genai.Client()
response = client.models.generate_content(
model="gemini-3-pro-image-preview",
contents=["A cute banana character with sunglasses"],
config=types.GenerateContentConfig(
response_modalities=['IMAGE']
)
)
for part in response.parts:
if part.inline_data is not None:
image = part.as_image()
image.save("tmp/generated.png")
print("Image saved to tmp/generated.png")
EOF
The # /// script block declares dependencies inline using TOML syntax. This makes scripts self-contained and reproducible.
Why these dependencies:
google-genai- Gemini API clientpillow- Required for.as_image()method (converts base64 to PIL Image) and saving images
Only write to files when:
- The script needs to be reused multiple times
- The script is complex and requires iteration
- The user explicitly asks for a saved script
Basic Template
uv run - << 'EOF'
# /// script
# dependencies = ["google-genai", "pillow"]
# ///
from google import genai
from google.genai import types
client = genai.Client()
# Generate image
response = client.models.generate_content(
model="gemini-3-pro-image-preview",
contents=["YOUR PROMPT HERE"],
config=types.GenerateContentConfig(
response_modalities=['IMAGE']
)
)
# Save result
for part in response.parts:
if part.text is not None:
print(part.text)
elif part.inline_data is not None:
image = part.as_image()
image.save("tmp/output.png")
print("Saved: tmp/output.png")
EOF
Key Principles
- Small scripts: Each script should do ONE thing (generate, refine, save)
- Evaluate output: Always save images and print status to decide next steps
- Use tmp/: Save generated images to tmp/ directory by default
- Stateless execution: Each script runs independently, no cleanup needed
Workflow Loop
Follow this pattern for complex tasks:
- Write a script to generate/process one image
- Run it and observe the output
- Evaluate - did it work? Check the saved image
- Decide - refine prompt or task complete?
- Repeat until satisfied
Image Configuration
Configure aspect ratio and resolution:
config=types.GenerateContentConfig(
response_modalities=['IMAGE'],
image_config=types.ImageConfig(
aspect_ratio="16:9", # "1:1", "16:9", "9:16", "4:3", "3:4"
image_size="2K" # "1K", "2K", "4K" (uppercase required)
)
)
Models
gemini-3-pro-image-preview- Fast, general purpose image generationgemini-3-pro-image-preview- Advanced, professional asset production (Nano Banana Pro)
Default to gemini-3-pro-image-preview (Nano Banana Pro) for all image generation unless:
- The user explicitly requests a different model
- The user wants to save budget/costs
- The user specifies a simpler or quick generation task
Nano Banana Pro provides higher quality results and should be the recommended choice.
Text + Image Output
To receive both text explanation and image:
config=types.GenerateContentConfig(
response_modalities=['TEXT', 'IMAGE']
)
Image Editing
Edit existing images by including them in the request:
uv run - << 'EOF'
# /// script
# dependencies = ["google-genai", "pillow"]
# ///
from google import genai
from google.genai import types
from PIL import Image
client = genai.Client()
# Load existing image
img = Image.open("input.png")
response = client.models.generate_content(
model="gemini-3-pro-image-preview",
contents=[
"Add a party hat to this character",
img
],
config=types.GenerateContentConfig(
response_modalities=['IMAGE']
)
)
for part in response.parts:
if part.inline_data is not None:
part.as_image().save("tmp/edited.png")
print("Saved: tmp/edited.png")
EOF
Debugging Tips
- Print response.parts to see what was returned
- Check for text parts - model may include explanations
- Save images immediately to verify output visually
- Use Read tool to view saved images after generation
Error Recovery
If a script fails:
- Check error message for API issues
- Verify GOOGLE_API_KEY is set
- Try simpler prompt to isolate the issue
- Check image format compatibility for edits
Advanced Scenarios
For complex workflows including thinking process, Google Search grounding, multi-turn conversations, and professional asset production, load references/guide.md.