promptel vs DSPy: Declarative Prompts vs Compilation

Comparing promptel and DSPy: when to use a declarative prompt specification, when to use a programmatic compiler, and how the two compose.

Why we get asked this question

Of all the comparisons we field, promptel vs DSPy is the one we hear most often. They both touch the same problem — making prompts first-class engineering artefacts rather than ad-hoc strings — but they attack it from different angles and arrive at very different artefacts. If you have an hour to evaluate, this post is designed to save you most of it.

The 30-second version: promptel is a specification format with a JavaScript runtime; DSPy is a Python framework with an optimiser. They are complementary, not competing, and they solve different halves of the problem.

What promptel is

promptel is a declarative prompt framework for Node.js. You write a prompt in its .prompt DSL or in an equivalent YAML format, declaring typed parameters, the prompt body, optional prompting techniques, and constraints such as maxTokens and temperature:

# summarise.yml
name: Summariser

meta:
  version: "1.0"
  description: Produce a three-bullet summary of input text

params:
  text:
    type: string
    required: true

body:
  text: |
    You are a precise summariser.
    Produce exactly 3 bullets, each under 120 characters.
    No preamble, no explanation.

    ${params.text}

constraints:
  maxTokens: 256
  temperature: 0.3

That file is the artefact. It can be diffed, reviewed in a PR, and versioned independently of the application code. The provider is chosen at execution time rather than written into the file:

const { executePrompt } = require('promptel');
const fs = require('fs');

const prompt = fs.readFileSync('summarise.yml', 'utf8');
const result = await executePrompt(prompt, { text: article }, {
  provider: 'claude',   // or 'openai', 'groq'
  apiKey: process.env.ANTHROPIC_API_KEY,
});

promptel also ships built-in techniques — chainOfThought, fewShot, zeroShot, treeOfThoughts, reAct and selfConsistency — and a CLI that executes prompts and converts between the DSL and YAML.

The companion tool, blogus, works on a different stage: it scans an existing codebase for OpenAI and Anthropic calls, moves the prompts into its own .prompt files (YAML frontmatter plus a template), and locks them with content hashes. Its files are not promptel specifications; the two tools are independent.

What DSPy is

DSPy is a Python framework for programming — not specifying — LLM behaviour. You write a Python module that describes the computation as a sequence of LLM calls, and DSPy’s optimisers (originally called “teleprompters”) tune the prompts and the few-shot examples empirically against a metric you provide:

import dspy

class Summarise(dspy.Signature):
    """Produce a 3-bullet summary of input text."""
    text: str = dspy.InputField()
    bullets: list[str] = dspy.OutputField()

summariser = dspy.ChainOfThought(Summarise)
teleprompter = dspy.MIPROv2(metric=summary_quality)
optimised = teleprompter.compile(
    summariser,
    trainset=eval_set,
    valset=val_set,
)

The output is also an artefact — a program whose optimised prompts and demos can be saved and reloaded — but it is not a declarative file. It is what you ship, but it is not what you diff, review, or hand to a non-engineer.

The dimensions that matter

DimensionpromptelDSPy
What you writeA .prompt DSL or YAML filePython code
What the artefact isA spec file checked into gitA Python program, plus saved optimised prompts and demos
Who can review itEngineers, and anyone comfortable reading YAMLMostly engineers
Where the optimisation happensOutside the spec; promptel does not optimise promptsInside the framework; optimisers such as MIPROv2 run against your metric
RuntimeNode.js 18+Python
Version control storyGit diff of a YAML or DSL file is the prompt diffPrompts are generated from signatures and optimiser state, so the diff is less direct
TypesTyped input parameters with required flags and defaults; an output format, not an output schemaTyped input and output fields on a dspy.Signature
Multi-providerOpenAI, Anthropic and Groq, selected per callMany providers through its LM configuration
Few-shot examplesWritten by you, via the fewShot techniqueNative: optimisers generate and select demos
CostNot addressed; a gateway such as route-switch can sit in frontNot a built-in objective, but you can fold cost into your metric

When to use which

Use promptel when:

  • The prompt is a contract that crosses a team boundary and needs to be diffable, reviewable and readable without running Python.
  • Your application is in JavaScript or TypeScript.
  • You want to switch between OpenAI, Anthropic and Groq without rewriting the prompt or the call site.
  • You want named prompting techniques (chain-of-thought, self-consistency and so on) expressed declaratively rather than hand-assembled.

Use DSPy when:

  • You are optimising prompts empirically against a metric and want the optimiser to generate few-shot demos.
  • You are doing research on prompt optimisation itself and want to compare optimisers (MIPROv2, COPRO and others).
  • Your prompt logic is programmatic — branches, retries, tool calls — and a static spec is too rigid.
  • You are prototyping in Python and want to iterate fast.

Use both when you want the reviewable artefact and the empirical optimisation: optimise in DSPy, then carry the winning instruction text into a promptel spec as the thing that ships and gets reviewed. That hand-off is manual — neither tool imports the other’s format — so treat it as a deliberate step with its own review, not an automated pipeline.

A workflow that uses both

  1. Spec the prompt in promptel. Declare the parameters, the constraints and a first draft of the body. This is what a reviewer sees.
  2. Optimise the wording with DSPy. Build an equivalent dspy.Signature, run an optimiser against a labelled eval set, and take the best instruction text and demos.
  3. Commit both. The promptel spec, the eval set, the optimiser configuration and the metric all go into the repository, so the optimisation can be rerun.
  4. Run it against more than one provider. The same spec runs on OpenAI, Anthropic or Groq by changing the provider option, and you should test it on each: portability of the file is not portability of behaviour.
  5. Lock what ships. If your prompts are embedded in application code, blogus can hash and lock them so that CI fails when a prompt changes without review.

If you also want to optimise against production traffic rather than a fixed eval set, route-switch reruns MIPROv2 against traces it captures at the gateway.

Things people get wrong

  • They treat them as alternatives. They mostly aren’t. promptel is about the artefact; DSPy is about finding good content for it.
  • They expect DSPy to be an audit trail. DSPy is built for optimisation. A record of what was deployed needs version control and, ideally, a lock file.
  • They use promptel for throwaway code. The spec overhead is real; for an afternoon’s prototype, raw strings are fine. Reserve specs for prompts that will outlive the afternoon.
  • They assume a typed spec validates the answer. promptel types the inputs. Checking that the model’s output has the shape you asked for is still your test suite’s job.