Skip to content

Managing prompts with Dotprompt

Prompt engineering is the primary way that you, as an app developer, influence the output of generative AI models. For example, when using LLMs, you can craft prompts that influence the tone, format, length, and other characteristics of the models’ responses.

The way you write these prompts will depend on the model you’re using; a prompt written for one model might not perform well when used with another model. Similarly, the model parameters you set (temperature, top-k, and so on) will also affect output differently depending on the model.

Getting all three of these factors—the model, the model parameters, and the prompt—working together to produce the output you want is rarely a trivial process and often involves substantial iteration and experimentation. Genkit provides a library and file format called Dotprompt, that aims to make this iteration faster and more convenient.

Dotprompt is designed around the premise that prompts are code. You define your prompts along with the models and model parameters they’re intended for separately from your application code. Then, you (or, perhaps someone not even involved with writing application code) can rapidly iterate on the prompts and model parameters using the Genkit Developer UI. Once your prompts are working the way you want, you can import them into your application and run them using Genkit.

Your prompt definitions each go in a file with a .prompt extension. Here’s an example of what these files look like:

---
model: googleai/gemini-flash-latest
config:
temperature: 0.9
input:
schema:
location: string
style?: string
name?: string
default:
location: a restaurant
---
You are the world's most welcoming AI assistant and are currently working at {{location}}.
Greet a guest{{#if name}} named {{name}}{{/if}}{{#if style}} in the style of {{style}}{{/if}}.

The portion in the triple-dashes is YAML front matter, similar to the front matter format used by GitHub Markdown and Jekyll; the rest of the file is the prompt, which can optionally use Handlebars templates. The following sections will go into more detail about each of the parts that make a .prompt file and how to use them.

Before reading this page, you should be familiar with the content covered on the Generating content with AI models page.

If you want to run the code examples on this page, first complete the steps in the Getting started guide for your language:

Complete the Get started guide. All examples assume you have already installed Genkit as a dependency in your project.

Although Dotprompt provides several different ways to create and load prompts, it’s optimized for projects that organize their prompts as .prompt files within a single directory (or subdirectories thereof). This section shows you how to create and load prompts using this recommended setup.

The Dotprompt library expects to find your prompts in a directory at your project root and automatically loads any prompts it finds there. By default, this directory is named prompts. For example, using the default directory name, your project structure might look something like this:

your-project/
├── lib/
├── node_modules/
├── prompts/
│ └── hello.prompt
├── src/
├── package-lock.json
├── package.json
└── tsconfig.json

If you want to use a different directory, you can specify it when you configure Genkit:

const ai = genkit({
promptDir: './llm_prompts',
// (Other settings...)
});

There are two ways to create a .prompt file: using a text editor, or with the developer UI.

If you want to create a prompt file using a text editor, create a text file with the .prompt extension in your prompts directory: for example, prompts/hello.prompt.

Here is a minimal example of a prompt file:

---
model: googleai/gemini-flash-latest
---
You are the world's most welcoming AI assistant. Greet the user and offer your assistance.

The portion in the dashes is YAML front matter, similar to the front matter format used by GitHub markdown and Jekyll; the rest of the file is the prompt, which can optionally use Handlebars templates. The front matter section is optional, but most prompt files will at least contain metadata specifying a model. The remainder of this page shows you how to go beyond this, and make use of Dotprompt’s features in your prompt files.

You can also create a prompt file using the model runner in the developer UI. Start with application code that imports the Genkit library and configures it to use the model plugin you’re interested in:

import { genkit } from 'genkit';
// Import the model plugins you want to use.
import { googleAI } from '@genkit-ai/google-genai';
const ai = genkit({
// Initialize and configure the model plugins.
plugins: [
googleAI({
apiKey: 'your-api-key', // Or (preferred): export GEMINI_API_KEY=...
}),
],
});

It’s okay if the file contains other code, but the above is all that’s required.

Load the developer UI in the same project:

Terminal window
genkit start -- tsx --watch src/your-code.ts

In the Models section, choose the model you want to use from the list of models provided by the plugin.

Then, experiment with the prompt and configuration until you get results you’re happy with. When you’re ready, press the Export button and save the file to your prompts directory.

After you’ve created prompt files, you can run them from your application code, or using the tooling provided by Genkit. Regardless of how you want to run your prompts, first start with application code that imports the Genkit library and the model plugins you’re interested in.

If you’re storing your prompts in a directory other than the default, be sure to specify it when you configure Genkit.

To use a prompt, first load it using the prompt('file_name') method:

const helloPrompt = ai.prompt('hello');

Once loaded, you can call the prompt like a function:

const response = await helloPrompt();
// Alternatively, use destructuring assignments to get only the properties
// you're interested in:
const { text } = await helloPrompt();

Or you can also run the prompt in streaming mode:

const { response, stream } = helloPrompt.stream();
for await (const chunk of stream) {
console.log(chunk.text);
}
// optional final (aggregated) response
console.log((await response).text);

A callable prompt takes two optional parameters: the input to the prompt (see the section below on specifying input schemas), and a configuration object, similar to that of the generate() method. For example:

const response2 = await helloPrompt(
// Prompt input:
{ name: 'Ted' },
// Generation options:
{
config: {
temperature: 0.4,
},
},
);

Similarly for streaming:

const { stream } = helloPrompt.stream(input, options);

Any parameters you pass to the prompt call will override the same parameters specified in the prompt file.

See Generate content with AI models for descriptions of the available options.

As you’re refining your app’s prompts, you can run them in the Genkit developer UI to quickly iterate on prompts and model configurations, independently from your application code.

Load the developer UI from your project directory:

Terminal window
genkit start -- tsx --watch src/your-code.ts

Once you’ve loaded prompts into the developer UI, you can run them with different input values, and experiment with how changes to the prompt wording or the configuration parameters affect the model output. When you’re happy with the result, you can click the Export prompt button to save the modified prompt back into your project directory.

In the front matter block of your prompt files, you can optionally specify model configuration values for your prompt:

---
model: googleai/gemini-flash-latest
config:
temperature: 1.4
topK: 50
topP: 0.4
maxOutputTokens: 400
stopSequences:
- "<end>"
- "<fin>"
---

These values map directly to the configuration parameters:

const response3 = await helloPrompt(
{},
{
config: {
temperature: 1.4,
topK: 50,
topP: 0.4,
maxOutputTokens: 400,
stopSequences: ['<end>', '<fin>'],
},
},
);

See Generate content with AI models for descriptions of the available options.

Beyond model configuration, the front matter can set several execution-level fields that control how a prompt runs its model and tool loop:

  • maxTurns caps how many model/tool iterations a single prompt run may perform before stopping. This applies to tool-calling prompts, where the model may call tools across several turns. It defaults to 5.
  • returnToolRequests returns the model’s tool-call requests instead of automatically executing the tools and continuing the loop. Use it when you want to inspect, gate, or manually handle tool calls before running them. It defaults to false.
  • use attaches middleware to the prompt’s model loop by name, with optional config. Each entry is either a bare middleware name or a map with a name and a config. The code equivalent passes the middleware and its configuration directly instead of naming it, so nothing has to be registered first.
---
model: googleai/gemini-flash-latest
tools:
- getAttractions
- getFlightInfo
maxTurns: 10
returnToolRequests: false
use:
- skills # bare middleware name
- name: retry # name plus config map
config:
maxRetries: 3
---
Plan a trip using the available tools.

The middleware referenced by use must be registered so the name resolves at runtime. Register each middleware when you configure Genkit, and see the Middleware page for the available middleware and their configuration.

Register the middleware plugins from @genkit-ai/middleware with .plugin():

import { genkit } from 'genkit';
import { googleAI } from '@genkit-ai/google-genai';
import { retry, skills } from '@genkit-ai/middleware';
const ai = genkit({
plugins: [googleAI(), retry.plugin(), skills.plugin()],
});

You can specify input and output schemas for your prompt by defining them in the front matter section:

---
model: googleai/gemini-flash-latest
input:
schema:
theme?: string
default:
theme: "pirate"
output:
schema:
dishname: string
description: string
calories: integer
allergens(array): string
---
Invent a menu item for a {{theme}} themed restaurant.

These schemas are used in much the same way as those passed to a generate() request or a flow definition. For example, the prompt defined above produces structured output:

const menuPrompt = ai.prompt('menu');
const {