Skip to content
Dashboard

Veo 3.1

Veo 3.1 is Google's flagship video model in the Veo 3.1 generation on AI Gateway, the quality ceiling of that generation, with strong motion fidelity, native audio-visual synchronization, and image-to-video support for professional production workflows. Your use is subject to Google's Terms & Privacy Policies.

text-to-videoimage-to-video
import { experimental_generateVideo as generateVideo } from 'ai';
const result = await generateVideo({
model: 'google/veo-3.1-generate-001',
prompt: 'A serene mountain lake at sunrise.'
});
Read docs

Getting started

Generate videos with Veo 3.1 using the experimental_generateVideo function from AI SDK 6 or later. AI Gateway handles routing and polls until the video is ready.

Install the AI SDK (pnpm add ai dotenv), create an API key from the API Keys page, and set it as AI_GATEWAY_API_KEY in your environment. Full setup is covered in the video generation quickstart.

index.ts
import { experimental_generateVideo as generateVideo } from 'ai';
import fs from 'node:fs';
import 'dotenv/config';
async function main() {
const result = await generateVideo({
model: 'google/veo-3.1-generate-001',
prompt:
'A pangolin curled on a mossy stone in a glowing bioluminescent forest',
generateAudio: true,
});
// Save the generated video
fs.writeFileSync('output.mp4', result.videos[0].uint8Array);
console.log('Video saved to output.mp4');
}
main().catch(console.error);

Top-level parameters

Load the supported top-level parameters: prompt, aspectRatio, duration, resolution, and generateAudio.

top-level-params.ts
import { experimental_generateVideo as generateVideo } from 'ai';
import fs from 'node:fs';
import 'dotenv/config';
async function main() {
const result = await generateVideo({
model: 'google/veo-3.1-generate-001',
prompt:
'A pangolin curled on a mossy stone in a glowing bioluminescent forest',
aspectRatio: '16:9',
duration: 8,
resolution: '1080p',
generateAudio: true,
});
// Save the generated video
fs.writeFileSync('output.mp4', result.videos[0].uint8Array);
console.log('Video saved to output.mp4');
}
main().catch(console.error);
ParameterTypeRequiredDescription
promptstringNoText description of the video to generate.
duration4 | 6 | 8NoVideo length in seconds. 4 or 6 or 8 seconds.
resolutionstringNoResolution ('1280x720', '1920x1080', '3840x2160').
aspectRatiostringNoAspect ratio ('16:9', '9:16').
generateAudiobooleanNoGenerate synchronized audio with the video.
frameImagesArray<{ image: string; frameType: 'first_frame' | 'last_frame' }>NoFirst and last frames of the clip. A first_frame entry replaces prompt.image and wins when both are set, and adding a last_frame makes Veo animate from the first frame toward the last.
inputReferencesArray<string>NoReference images that guide the assets and style of the scene you describe in the prompt. They are not used as the first frame, and there is no prompt syntax for addressing them individually. Images only.

Input limits

InputFormatsSourcesMax countMax sizeLimits
Imagejpg, jpeg, pngurl, base64320 MB
Videomp4url1

Provider options

Pass Veo-specific options under providerOptions.vertex. This call loads every text-to-video option that combines in a single request. resizeMode is image-to-video only (see below), while referenceImages and gcsOutputDirectory change the inputs/output destination and are omitted here.

provider-options.ts
import { experimental_generateVideo as generateVideo } from 'ai';
import fs from 'node:fs';
import 'dotenv/config';
async function main() {
const result = await generateVideo({
model: 'google/veo-3.1-generate-001',
prompt:
'A pangolin curled on a mossy stone in a glowing bioluminescent forest',
generateAudio: true,
providerOptions: {
vertex: {
enhancePrompt: true,
negativePrompt: 'blurry, low quality, distorted',
personGeneration: 'allow_adult',
compressionQuality: 'optimized',
sampleCount: 1,
seed: 42,
pollIntervalMs: 5000,
pollTimeoutMs: 600000,
},
},
});
// Save the generated video
fs.writeFileSync('output.mp4', result.videos[0].uint8Array);
console.log('Video saved to output.mp4');
}
main().catch(console.error);

Pass Veo-specific options under providerOptions.vertex in your generateVideo call.

ParameterTypeRequiredDescription
enhancePromptbooleanNoUse Gemini to enhance prompts. Defaults to true.
negativePromptstringNoWhat to discourage in the generated video.
personGeneration'dont_allow' | 'allow_adult' | 'allow_all'NoWhether to allow person generation. Defaults to 'allow_adult'.
compressionQuality'optimized' | 'lossless'NoCompression quality. Defaults to 'optimized'.
sampleCountnumberNoNumber of output videos (1-4).
seednumberNoSeed for deterministic generation (0-4,294,967,295).
gcsOutputDirectorystringNoCloud Storage URI to store the generated videos.
referenceImagesarrayNoReference images for style or asset guidance. Legacy alternative to the top-level inputReferences, used only when inputReferences is omitted.
resizeMode'pad' | 'crop'NoImage-to-video only: how to resize the input image to fit video dimensions. Defaults to 'pad'.
pollIntervalMsnumberNoHow often to check task status. Defaults to 5000.
pollTimeoutMsnumberNoMaximum wait time. Defaults to 600000 (10 minutes).

Duration and resolution

1080p and 4K require duration: 8. At 720p, you can use 4, 6, or 8 seconds.

Frames take priority over references

Frames and references are mutually exclusive. When frameImages is set, inputReferences and the legacy providerOptions.vertex.referenceImages are ignored.

The top-level parameters win over their provider-option equivalents: frameImages overrides prompt.image, and inputReferences overrides providerOptions.vertex.referenceImages.

Image to video

Animate a starting image by passing prompt as an object with image and an optional text field.

image-to-video.ts
import { experimental_generateVideo as generateVideo } from 'ai';
import fs from 'node:fs';
import 'dotenv/config';
async function main() {
const result = await generateVideo({
model: 'google/veo-3.1-generate-001',
prompt: {
image: 'https://example.com/landscape.png',
text: 'Camera slowly pans across the scene as clouds drift by',
},
duration: 8,
resolution: '1080p',
generateAudio: true,
providerOptions: {
vertex: {
resizeMode: 'crop',
},
},
});
// Save the generated video
fs.writeFileSync('output.mp4', result.videos[0].uint8Array);
console.log('Video saved to output.mp4');
}
main().catch(console.error);

First and last frame

Transition between a starting and ending image. Pass both frames through the top-level frameImages, tagging one first_frame and one last_frame. Veo animates from the first frame toward the last.

veo-first-last-frame.ts
import { experimental_generateVideo as generateVideo } from 'ai';
import fs from 'node:fs';
import 'dotenv/config';
async function main() {
const result = await generateVideo({
model: 'google/veo-3.1-generate-001',
prompt: '360 pan from the first frame to the last frame',
frameImages: [
{ image: 'https://example.com/start.png', frameType: 'first_frame' },
{ image: 'https://example.com/end.png', frameType: 'last_frame' },
],
aspectRatio: '16:9',
resolution: '720p',
duration: 8,
});
// Save the generated video
fs.writeFileSync('output.mp4', result.videos[0].uint8Array);
console.log('Video saved to output.mp4');
}
main().catch(console.error);

Reference to video

Guide the assets and style of a generated scene with reference images passed through the top-level inputReferences. The references are not used as the first frame, and Veo has no prompt syntax for addressing them individually — describe how they should appear in the scene instead.

veo-reference-to-video.ts
import { experimental_generateVideo as generateVideo } from 'ai';
import fs from 'node:fs';
import 'dotenv/config';
async function main() {
const result = await generateVideo({
model: 'google/veo-3.1-generate-001',
prompt:
'The video opens with a medium shot of a woman in a high-fashion flamingo dress walking through a lagoon',
inputReferences: [
'https://example.com/dress.png',
'https://example.com/glasses.png',
'https://example.com/woman.png',
],
aspectRatio: '16:9',
duration: 8,
generateAudio: true,
});
// Save the generated video
fs.writeFileSync('output.mp4', result.videos[0].uint8Array);
console.log('Video saved to output.mp4');
}
main().catch(console.error);