Skip to content

Fetching Composers

A composer is a document template that combines static HTML segments with prompt references. getComposer() fetches a composer, interpolates your variables, and resolves AI models. Then compose() runs every prompt in parallel and assembles the final output — all in one line.

import { createPromptlyClient } from '@promptlycms/prompts';
import { generateText } from 'ai';
const promptly = createPromptlyClient();
const { compose } = await promptly.getComposer('article-composer', {
input: { topic: 'TypeScript', audience: 'developers' },
});
// One line — runs all prompts in parallel and assembles the output
const output = await compose(generateText);
  1. FetchgetComposer() calls the Promptly API and gets the composer’s segment array
  2. Interpolate — Template variables (${var} in prompts, {{var}} in static HTML) are replaced with your input values
  3. Resolve models — Each prompt segment’s model is resolved to an AI SDK LanguageModel
  4. Composecompose() passes each prompt to your generate function, runs them in parallel via Promise.all, and assembles the static HTML + AI text into a single string

Composer output preserves authoring line breaks by default. Empty rich-text paragraphs from static segments stay visible, text prompt output placed in its own rich-text paragraph keeps a visible email-safe paragraph gap, and newlines in generated text are emitted as <br> tags. Raw html_block segments remain opaque except for variable interpolation.

Pass a wrapper function to customise parameters for every prompt:

const output = await compose((prompt) =>
generateText({ ...prompt, maxTokens: 500 })
);

The prompt argument has the shape { model, system, prompt, temperature, promptId, promptName }, so you can spread it and override individual fields.

const composer = await promptly.getComposer('my-composer', {
input: { text: 'Hello world', targetLang: 'French' },
});
composer.composerId; // 'my-composer'
composer.composerName; // 'My Composer'
composer.version; // '1.0.0'
composer.config; // { schema, inputData, inputDataRootName }
composer.segments; // raw segment array from the API

By default, getComposer() fetches the latest published version. Pin to a specific version:

const { compose } = await promptly.getComposer('my-composer', {
version: '2.0.0',
input: { text: 'Hello world' },
});

Use getComposers() to fetch multiple composers in parallel:

const [emailComposer, reportComposer] = await promptly.getComposers([
{ composerId: 'email-composer', input: { name: 'Alice' } },
{ composerId: 'report-composer', version: '2.0.0', input: { quarter: 'Q1' } },
]);
const emailOutput = await emailComposer.compose(generateText);
const reportOutput = await reportComposer.compose(generateText);

A Next.js API route that fetches a composer and returns the assembled document:

app/api/generate-report/route.ts
import { createPromptlyClient } from '@promptlycms/prompts';
import { generateText } from 'ai';
const promptly = createPromptlyClient();
export const POST = async (req: Request) => {
const { companyName, quarter } = await req.json();
const { compose } = await promptly.getComposer('quarterly-report', {
input: { companyName, quarter },
});
const report = await compose(generateText);
return new Response(report, {
headers: { 'Content-Type': 'text/html' },
});
};

If you have run codegen, the composer ID narrows to generated IDs and the input object is fully typed to the exact variables defined in the CMS. Without codegen, composer IDs accept any string and inputs fall back to Record<string, unknown>.