What is Miniscript?
Learn what Miniscript is, why it exists, how it compiles to Bitcoin Script, and how it makes complex Bitcoin policies analyzable and safer.

Introduction
Miniscript is a structured way to write a subset of Bitcoin Script so that complex spending conditions become easier to compose, analyze, and sign safely. That matters because raw Bitcoin Script is powerful enough to express many useful custody policies, but awkward enough that even experienced developers can make scripts that are hard to inspect, hard to fee-estimate, or subtly unsafe. Miniscript does not give Bitcoin new consensus features. Instead, it changes how we describe and reason about the script features Bitcoin already has.
The puzzle Miniscript solves is simple: if Script is already the language the network runs, why invent another language on top of it? The answer is that Bitcoin Script is optimized for execution by nodes, not for design by humans or tooling. A script may be valid on-chain and yet still be difficult for a wallet to understand generically. A signer may not know which witness to produce, a coordinator may not know the maximum fee impact of a spend path, and an auditor may not know whether a policy can be satisfied non-malleably. Miniscript exists because expressiveness alone is not enough; for real systems, you also need predictable structure.
In practice, Miniscript is used inside Bitcoin output descriptors, especially wsh() descriptors for P2WSH and tr() descriptors for Taproot script paths. The canonical specification applies to P2WSH and Tapscript, and explicitly excludes bare scripts and P2SH as specified targets, even though some constructions can work elsewhere. That scope matters: many of Miniscript's safety and cost assumptions are tied to SegWit and, for Taproot, to Tapscript-specific rules.
Why is raw Bitcoin Script hard for wallets and tools to analyze?
| Problem | Raw Script | Miniscript benefit |
|---|---|---|
| Policy intent | Encode intent as stack program | Express intent as tree policy |
| Witness ambiguity | Signer unsure which witness | Explicit satisfaction paths |
| Fee/size bounds | Worst-case unknown | Static witness size bounds |
| Composition safety | Hard to compose safely | Type-checked composability |
Bitcoin Script is a stack machine. It does not ask you to state a policy like “Alice and Bob can spend together, or Alice alone after 90 days.” It asks you to construct a program whose stack behavior produces that effect. Those are not the same task. The first is about intent; the second is about execution mechanics.
That gap is where complexity enters. A wallet that sees arbitrary Script cannot generally infer, in a reliable and structured way, what data is needed to spend it, what witness sizes are possible, whether dissatisfaction paths are safe to use in branches, or whether third parties can malleate the witness. Some scripts are easy to understand locally but difficult to understand compositionally. You may know what an OP_CHECKSIG does, and still not know whether a larger script containing it is safe to compile, sign, and broadcast automatically.
The core difficulty is that raw Script is too unconstrained. Two scripts can mean nearly the same thing while having very different analysis properties. A human expert can often reason through them, but generic software needs stronger guarantees than “probably fine.” Wallet interoperability especially suffers here. If one tool creates a script and another tool is asked to sign it, both need a common, machine-checkable understanding of what counts as satisfaction, what counts as dissatisfaction, and which spend paths remain within Bitcoin’s policy and consensus limits.
Miniscript addresses this by restricting Script to a subset with a clear tree structure and known local properties. The restriction is the feature. By giving up arbitrary Script cleverness, you gain the ability to ask global questions and get trustworthy answers.
How does Miniscript treat Script as composable policy fragments?
The easiest way to understand Miniscript is to stop thinking of it as “a nicer syntax for Script” and instead think of it as a library of script fragments with declared behavior. Each fragment corresponds to a concrete Bitcoin Script template, but it also carries metadata about how it behaves on the stack, how it is satisfied, whether it can be dissatisfied, and whether it composes safely with other fragments.
That is the compression point. Miniscript works because every building block is not just an opcode sequence; it is an opcode sequence plus a set of proven properties. Once those properties are known for small pieces, they can be combined to reason about larger policies.
Some fragments represent primitive conditions such as a public-key signature check, a hash preimage requirement, or a timelock. Others combine subexpressions using conjunctions, disjunctions, or thresholds. The result is that a policy is represented as a tree. That tree is much closer to how humans think about spending conditions: “all of these,” “either this or that,” “at least k of these conditions,” and so on.
The Rust documentation describes Miniscript, at a high level, as a monotone function: a tree of ANDs, ORs, and thresholds over signature checks, hashlocks, and timelocks. “Monotone” here means the language is built around positive satisfaction conditions rather than arbitrary negation. That design is not aesthetic. It is what makes satisfaction analysis tractable and generic witness construction possible.
Example: express a delayed‑recovery multisig in Miniscript
Consider a policy you might actually want for long-term storage: Alice and Bob can spend together immediately, but if Bob disappears then Alice alone can recover the funds after 30 days.
In raw Script, you could encode that policy directly, but the resulting script would be something a specialized engineer would want to inspect carefully. A generic wallet would have to recover not just the policy, but the exact witness structure for each branch, the effect of the timelock, and the weight of the worst-case satisfaction.
In Miniscript, the same idea is expressed structurally. You would describe a branch requiring both keys, and another branch requiring Alice plus an older() condition. That expression then compiles to ordinary Bitcoin Script. The network never sees “Miniscript” as such; it sees the resulting script and witness. But before you ever broadcast anything, your software can answer the questions that matter: which signatures are needed now, which signatures are needed later, what witness data each path requires, whether the timelock is relative, whether the witness can be produced non-malleably, and how large the witness can become.
That last point is more important than it sounds. In Bitcoin, fee estimation and spend reliability depend on knowing worst-case witness sizes and resource consumption. If a wallet cannot bound those statically, a script may be valid in theory but operationally painful or dangerous in practice. Miniscript’s structure makes those bounds analyzable.
How does Miniscript compile into Bitcoin Script and on‑chain outputs?
Miniscript is not interpreted by Bitcoin nodes. It is compiled into ordinary Script according to a translation table of fragments. The specification defines each fragment in terms of both semantics and concrete Script encoding. This means Miniscript is not an alternative execution environment. It is a disciplined source language for a subset of the existing one.
That distinction helps avoid a common misunderstanding. Miniscript does not “extend” Bitcoin Script in the consensus sense. If Bitcoin Script could not enforce a condition before, Miniscript cannot conjure that condition into existence. What Miniscript adds is structure and analyzability at the authoring layer.
Because the mapping is explicit, toolchains can parse a Miniscript expression, compile it to Script, or in some cases infer a Miniscript descriptor from an existing script when enough information is available. Bitcoin Core release notes reflect this operational role. Support first appeared for P2WSH Miniscript descriptors in wsh(), initially in watch-only and RPC contexts, and later descriptor wallets gained the ability to spend P2WSH Miniscript outputs. Bitcoin Core 26.0 extended this to Taproot descriptors, allowing Miniscript expressions inside Taproot leaves.
So the mechanical picture is straightforward: a descriptor such as wsh(...) or tr(...) contains a Miniscript expression; that expression expands to a script; the script is committed to in the output; and later a satisfier provides the witness data needed for one valid spend path.
What does Miniscript’s type system check and why does it matter?
| Type | Stack role | Guarantee | When used |
|---|---|---|---|
| B (Base) | Pushes or checks values | Consensus soundness | Primitive fragments |
| V (Verify) | Verifies stack top | No extra stack args | Post-check wrappers |
| K (Key) | Signature checks | Standardness completeness | Pubkey fragments |
| W (Wrapped) | Wraps behaviour of nodes | Enables composition | Complex combinators |
Miniscript’s most important feature is not its syntax. It is its type system.
The specification assigns every Miniscript expression one of four basic correctness types: B, V, K, and W. Very roughly, these describe how the fragment interacts with the stack and in what form it produces success. On top of those basic types, modifiers such as z, o, n, d, and u describe further guarantees, such as whether an expression needs zero or one stack arguments, whether it can be dissatisfied, and whether its success form is unit-like.
If that sounds abstract, the practical meaning is simple: the type system tells you whether fragments fit together without needing to execute the script. Instead of discovering at runtime that a branch leaves the wrong thing on the stack, Miniscript rejects invalid compositions statically.
This is why Miniscript can promise more than readability. The type system is designed to guarantee consensus soundness and standardness completeness, and more generally to support static reasoning about correctness. Consensus soundness means you should not be able to construct a consensus-valid witness unless the intended spending conditions are actually met. Standardness completeness means that satisfactions the language claims exist can be represented in ways acceptable under standard relay policy. Those are exactly the guarantees you want if software is going to automate script creation and signing.
A useful way to see this is to compare Miniscript with arbitrary Script macros. A macro system can make scripts shorter to write, but unless it carries formal composition rules, it does not let independent tools reason safely about the result. Miniscript’s types are what turn “pretty syntax” into a machine-checkable contract.
What's the difference between satisfaction and dissatisfaction in Miniscript?
When people first meet Script, they often focus only on successful spends: what witness makes the script evaluate to true? Miniscript forces a second question: what witness, if any, deliberately makes a subexpression evaluate to false without aborting execution?
That is the distinction between satisfaction and dissatisfaction, and it matters because many larger constructions depend on cleanly choosing between branches. If an OR-like combinator is going to try one branch and then another, the non-chosen branch often needs a controlled dissatisfaction, not a script failure. Miniscript tracks this explicitly.
This is also why some modifiers describe dissatisfiability properties. They are not cosmetic annotations. They determine whether a fragment can be safely embedded inside larger branch structures. In raw Script, this kind of reasoning is easy to get wrong because “false” and “abort” are both ways not to succeed, but they behave very differently when composed.
Once satisfactions and dissatisfactions are explicit, a generic signer can recursively compute witnesses for the whole expression. The specification includes an algorithm that walks the tree, determines optimal satisfactions and dissatisfactions for subexpressions, and combines them into an overall witness. That is a major part of what makes generic signing possible: wallets do not need handwritten code for each script template.
How does Miniscript reduce witness malleability and optimize cost?
Miniscript was designed not just to find a valid witness, but to reason about non-malleable witnesses and choose optimal ones. This is important because a script that admits many alternative satisfactions can create practical problems. Third parties may be able to alter witnesses, fees may become harder to estimate, and protocols that rely on revealing exactly one branch or one preimage can become more fragile.
The specification therefore adds a separate malleability analysis with properties such as s, f, and e, and defines a recursive algorithm for selecting non-malleable satisfactions where possible. The details are technical, but the core mechanism is intuitive: when multiple ways to satisfy a tree exist, Miniscript prefers ones that avoid unnecessary malleability and minimize cost.
This is one of the clearest examples of why structure matters. In arbitrary Script, “find the cheapest safe witness” is not a generic operation. In Miniscript, it becomes possible because each node advertises enough local information for a recursive optimizer to work.
Still, this is also a place to be precise about assumptions. Some non-malleability claims depend on an attacker model: for example, assumptions about who has private keys, whether extra preimages exist, and how many valid witnesses an adversary gets to observe. If those assumptions change, the analysis can change with them. Miniscript improves the situation dramatically, but it does not repeal the underlying subtleties of Script-based protocols.
How does Miniscript help you check Bitcoin resource and standardness limits?
A Bitcoin script is only useful if its spending paths fit within the network’s rules. That includes consensus limits and standardness limits on script size, opcode counts, stack elements, and witness structure. Raw Script lets you build something that looks logically correct but turns out to be impractical or non-standard along some branch.
Miniscript makes resource analysis a first-class part of the language. Because the expression is structured, software can statically compute whether none, some, or all spending paths hit relevant limits. For P2WSH, standardness rules such as script-size limits matter directly. For Tapscript, some limits differ, so the analysis changes accordingly.
This is not just an implementation convenience. It changes what it means to design a policy. A custody setup is not merely the set of conditions under which money may move; it is the set of conditions under which money may move within Bitcoin’s operational envelope. Miniscript keeps those two notions aligned.
The Taproot port made this especially clear. When Miniscript was extended to Tapscript in Bitcoin Core, resource accounting had to adapt to changes such as 32-byte key serialization, 64-byte signatures, modified limits, and stack-execution concerns. The implementation introduced tracking of execution-time stack growth so spending paths would not unexpectedly exceed MAX_STACK_SIZE during script execution. That is the kind of hidden operational detail Miniscript is meant to surface before funds are at risk.
Which Bitcoin tools and libraries support Miniscript and descriptors?
| Tool | Role | Miniscript features | Spend support |
|---|---|---|---|
| rust-miniscript | Library for analysis | Compile, analyze, witness | Tooling library |
| Bitcoin Core | Node + descriptor RPCs | wsh()/tr() Miniscript descriptors | Descriptor wallet spending |
| BDK | Wallet SDK | Descriptor + policy compilation | Yes; wallet support |
| Hardware wallets | Device signer | Timelock and recovery flows | Depends on integration |
Miniscript is most useful when paired with output descriptors. Descriptors answer the question “what kind of output is this and how do keys fit into it?” Miniscript answers the deeper question “what spending policy does the script path enforce?” Together they form a standard, machine-readable description that wallets and libraries can exchange.
That is why support in libraries and wallets tends to show up through descriptor tooling. The rust-miniscript library can parse and serialize descriptors, compile abstract policies to Miniscript, analyze satisfiability, encode and decode Script, and construct optimal witnesses. Bitcoin Dev Kit is built on top of rust-miniscript, which is one reason Miniscript has become relevant in practical wallet engineering rather than remaining a research curiosity.
Bitcoin Core’s trajectory shows the same pattern. Version 24.0.1 added wsh() Miniscript descriptor support in several RPCs and watch-only wallets. Version 25.0 added spending support for P2WSH Miniscript descriptors in descriptor wallets and improved PSBT finalization for Miniscript-compatible P2WSH scripts. Version 26.0 extended descriptor and PSBT support to Taproot leaves. In other words, Miniscript moved from “you can describe and inspect these scripts” to “wallets can actually spend them.”
Hardware and end-user tooling have started to reflect that maturation. Blockstream Jade announced Miniscript support through the Liana wallet flow, using timelocks and secondary keys for recovery-oriented custody. That is a good example of Miniscript’s real niche: not exotic on-chain programming for its own sake, but robust expression of human custody policies like inheritance, delayed recovery, escrow, and layered authorization.
What use cases and custody policies are best suited to Miniscript?
The best way to describe Miniscript’s practical role is this: it turns advanced Bitcoin custody policies into something software can handle generically. If you want a wallet that understands “2-of-3 now, 1-of-1 after a delay,” or “either cooperative spend or hash-preimage recovery before timeout,” Miniscript gives the wallet a structured representation instead of an opaque script blob.
That has several consequences. It makes multisig-plus-timelock designs easier to implement correctly. It makes PSBT finalization more tractable because signers and coordinators can agree on satisfactions mechanically. It makes fee estimation and branch analysis possible before broadcast. And it makes auditing easier because you can inspect policy structure instead of mentally simulating arbitrary Script.
What it is not for is arbitrary Script wizardry. If a construction falls outside the Miniscript subset, you lose the static guarantees that justify using Miniscript in the first place. That is not a weakness so much as the defining tradeoff.
What are Miniscript’s limitations and important assumptions?
Miniscript’s power comes from restriction, so its limitations follow directly from that choice.
First, it only covers a subset of Bitcoin Script. Some valid scripts are not representable, and some policies must be reformulated to fit the structured fragment system. If your goal is maximal expressiveness, Miniscript is the wrong abstraction. Its purpose is safe structure, not completeness over all Script idioms.
Second, applicability depends on context. The current specification is for P2WSH and Tapscript, with minor differences between them, and explicitly excludes bare scripts and P2SH as specification targets. Tooling may still discuss related contexts, but the strongest guarantees are tied to the specified environments.
Third, there are edge-case restrictions around timelocks. The specification disallows certain forms of timelock mixing in particular combinators, including some threshold constructions. This is easy to overlook if you think only at the policy level. A human may say “either after block height X or after time Y,” but those are not interchangeable conditions inside Script analysis. Miniscript makes that distinction explicit because otherwise the compiled template may not match user expectations or safe composition rules.
Finally, Miniscript implementations are software, and software can have bugs. That is not a theoretical caveat; it has happened. A known type-system bug around MINIMALIF led to unsafe generated scripts in some cases, and later a Rust library vulnerability involved stack consumption from improper tree-depth tracking. These incidents do not negate Miniscript’s value. In a way, they underline it: once you promise machine-checkable safety properties, implementation correctness becomes security-critical. The right lesson is not “structure is useless,” but “structured compilers and analyzers need the same scrutiny as cryptographic code.”
How does Miniscript relate to Bitcoin Script and Taproot in wallet design?
Miniscript sits in a very specific place in the Bitcoin stack. It is not below Script, because it does not change consensus. It is not above policy design in the vague sense of natural-language requirements, because it still maps closely to concrete spend conditions. It is a middle layer between human policy and executable Script.
That is why it relates naturally both to Bitcoin Script and to Taproot. Relative to raw Script, Miniscript removes unsafe flexibility and replaces it with analyzable templates. Relative to Taproot, Miniscript makes script-path spending conditions practical to author and reason about inside tr() descriptors. Taproot gives you a more efficient and private way to commit to script branches; Miniscript helps make those branches well-structured enough for software to manage.
A good way to remember this is: **Script is what Bitcoin executes; Miniscript is what robust Bitcoin tooling wants to reason about. **
Conclusion
Miniscript is a structured language for a subset of Bitcoin Script that makes complex spending conditions composable, analyzable, and signable by generic tools. Its key insight is that each script fragment should come with explicit behavioral guarantees, so larger policies can be checked statically instead of trusted by hand.
It does not make Bitcoin more expressive. It makes Bitcoin’s existing expressiveness usable for real wallet engineering. That is why Miniscript matters.
How do you get practical Bitcoin exposure after learning Miniscript?
After learning Miniscript, a practical next step is to get exposure to Bitcoin itself by buying or trading BTC on an exchange. Cube Exchange lets you fund an account with fiat or supported crypto and place spot orders on BTC markets, so you can move from protocol study to market exposure in a few steps.
- Fund your Cube account with fiat via the on‑ramp (card or bank transfer) or deposit a supported crypto like USDC/BTC from your wallet.
- Open the BTC/USDC or BTC/USD market on Cube and pick an order type. Use a limit order for price control or a market order for immediate execution.
- Enter the BTC amount or the fiat/USDC amount to spend, review the estimated fill, fees, and slippage, then submit the order.
- After the trade fills, optionally set a stop‑loss or take‑profit order to manage downside risk or lock in gains.
Frequently Asked Questions
- Is Miniscript a new Bitcoin scripting language that nodes run, or does it change consensus rules? +
- Miniscript is a disciplined source language for a subset of Bitcoin Script that compiles to ordinary Script (it is not interpreted by nodes or a new consensus feature); its value is making existing Script policies analyzable, composable, and safer for wallets and tooling rather than adding new on‑chain powers.
- Which script contexts and output types does Miniscript officially support? +
- The canonical Miniscript specification targets P2WSH (SegWit script hashes) and Tapscript (Taproot script paths) and explicitly excludes bare scripts and P2SH as specification targets, so the strongest guarantees are tied to those environments.
- How does a Miniscript policy actually become an on‑chain script and witness? +
- Miniscript expressions are compiled into ordinary Bitcoin Script according to a defined translation table of fragments; wallets and descriptor toolchains hold the Miniscript representation for analysis and witness construction, while the network only ever sees the compiled Script and witness.
- What role does Miniscript’s type system play and what kinds of things does it check? +
- The type system assigns each expression basic types (B, V, K, W) plus modifiers (z, o, n, d, u) that describe stack interaction, dissatisfiability, and other local guarantees so compositional correctness can be checked statically without executing the script.
- What’s the difference between satisfaction and dissatisfaction in Miniscript and why does it matter? +
- Satisfaction is what witness data makes a subexpression evaluate to true; dissatisfaction is a controlled way to make a subexpression evaluate to false without aborting execution, and Miniscript tracks both because many combinators require safe dissatisfactions to compose branches correctly.
- Does Miniscript guarantee non‑malleable witnesses for all scripts it expresses? +
- Miniscript includes a malleability analysis and a recursive optimizer that prefers non‑malleable and cost‑optimal satisfactions, but those guarantees depend on attacker model assumptions (e.g., who holds private keys and whether extra preimages exist), so non‑malleability cannot be asserted unconditionally.
- Are there spending policies or Script features that Miniscript cannot represent? +
- Because Miniscript is a restricted subset, some valid Bitcoin Script idioms cannot be represented and certain timelock mixings are disallowed (for example, mixing absolute vs relative or height vs time locks in some combinators and thresholds), so scripts or policies using those patterns must be reformulated or cannot benefit from Miniscript’s static guarantees.
- Which libraries and Bitcoin Core versions support Miniscript in practice, and can I rely on broad wallet support today? +
- Tooling and upstream software increasingly support Miniscript: rust‑miniscript and sipa’s C++ miniscript are reference implementations, Bitcoin Core added descriptor support incrementally (wsh() watch‑only in 24.0.1, P2WSH spending and PSBT improvements in 25.0, and Taproot leaf support in 26.0), and BDK builds on rust‑miniscript—however implementation differences and incomplete feature coverage mean you should check specific version notes before relying on a particular capability.
- Can Miniscript descriptors be reliably inferred from arbitrary existing on‑chain scripts? +
- Some tooling can infer a Miniscript descriptor from an existing script when enough structure is present, but inference is not universal and Bitcoin Core’s decodescript only infers ‘Miniscript‑compatible’ descriptors in limited cases; implementers should not assume full automatic round‑trip inference for arbitrary scripts.