Create your own
Lesson illustration

Understanding Program Derived Addresses (PDAs)

Welcome back. In the previous lesson, you used a Cross-Program Invocation (CPI) to have the System Program transfer SOL from a user wallet that signed the outer transaction. That pattern works when a human-controlled keypair authorizes the debit.

But many applications need funds, state, or permissions controlled by program logic rather than by a private key held by a person or server. A marketplace escrow, a protocol treasury, a per-user profile, and an SPL token vault all need this capability. Program Derived Addresses, usually called PDAs, are Solana’s mechanism for doing it.

By the end of this lesson, you should be able to explain what a PDA is, why it has no private key, how a program can use it as a controlled authority during a CPI, and why deterministic addresses are useful for structuring application state. This is a conceptual lesson; in the next module, you will derive and initialize PDAs in code.


The problem: a program cannot hold a private key

A normal wallet address comes from an Ed25519 keypair:

  • The public key identifies the account.
  • The private key produces signatures.
  • A wallet can sign a transaction because somebody controls that private key.

Your deployed Solana program does not have access to a private key. Even if a program needs to manage protocol-owned state or assets, you must not solve that by embedding a secret in the program binary or frontend. Anything deployed on-chain is publicly inspectable, and a frontend secret is not a secret at all.

Consider an escrow design:

  1. A buyer deposits funds into an escrow-controlled location.
  2. The program records the order state and release conditions.
  3. Later, a buyer, seller, or keeper submits a transaction requesting settlement.
  4. The program checks the order rules.
  5. Only if those checks pass may the escrow release assets.

At settlement time, the original buyer may not be the party submitting the transaction. More importantly, the funds must not depend on an ordinary wallet private key held by a developer or company operator. That would replace protocol rules with custodial trust.

A PDA addresses this problem. It is an address that is deterministically associated with a program, but deliberately has no corresponding private key.

Here is the essential comparison:

PropertyRegular keypair addressProgram Derived Address
Address sourceGenerated from a keypairDerived from program ID and seeds
Private keyExistsDoes not exist
Can sign an outer transactionYes, with its private keyNo
Can act as signer in a CPIOnly if it signed the outer transactionYes, through invoke_signed
Typical roleUser wallet, payer, external authorityProgram state, vault authority, escrow, configuration

The absence of a private key is not a limitation accidentally imposed on PDAs. It is the security property that makes them useful: no external actor can take control of the PDA by discovering, buying, leaking, or brute-forcing a key.


PDA: a deterministic address in a program-specific namespace

A PDA is derived from three conceptual inputs:

  1. Program ID: the public key of the program that will control the PDA.
  2. Seeds: application-defined byte values that describe what this PDA represents.
  3. Bump: a one-byte value used to ensure the resulting address is off the Ed25519 curve.

Conceptually:

The actual derivation includes additional domain separation and an off-curve check, but this model is enough for now: the same inputs always identify the same PDA.

For example, a program might use seed schemas like these:

Application objectConceptual seedsWhy it is useful
One global configuration account"config"Every client can independently locate the one expected configuration address.
One profile per user"profile", user public keyEach user gets a unique, predictable state account.
One vault per user and token mint"vault", user public key, mint public keyA token vault is scoped to both its user and asset.
One order record"order", creator public key, order numberThe address identifies a particular order without a lookup table.

The program ID matters. Two programs using identical seeds derive different addresses. This makes a PDA part of a program-specific namespace rather than a global name anyone can claim.

Deterministic addressing has a practical frontend benefit too. A React or TypeScript client does not need to ask a centralized database, “Where is this user’s profile?” Given the public program ID, the user public key, and the seed convention, it can derive the expected address locally and fetch it from RPC.

That does not make PDA derivation secret. It is meant to be public and reproducible. Security comes from the program validating the account, the seed scheme, required user signers, and its business rules.

Solana Bytes - Program Derived Addresses

Watch “Solana Bytes - Program Derived Addresses” from the Solana channel for a compact visual explanation of why applications need program-controlled addresses and why PDA derivation includes a bump.

Watch the overview. Focus on the distinction between a user-controlled private key and a program-derived address, then on why the bump ensures there is no corresponding private key. Treat the Web2 database analogy as motivation, while retaining this more precise rule: a program’s ownership of an account governs writes to its data; PDA signing is the mechanism that lets the program satisfy signer requirements during a CPI.


Off-curve addresses and the bump

Normal public keys are valid points on the Ed25519 curve. In principle, a valid on-curve public key could have a corresponding private key. That is appropriate for a wallet, but unacceptable for an address intended to be exclusively controlled by program logic.

A PDA must be off-curve. Because it is not a valid Ed25519 public key, no private key can exist for it.

The derivation process therefore tries a bump value until it finds an address that is off-curve. The SDK returns the resulting PDA together with the bump. Solana convention uses the canonical bump, the first successful bump found by the standard search process.

The canonical bump matters because a seed set can potentially have more than one off-curve result when paired with different bump values. If your client uses one valid bump while the program accepts another without a clear policy, you have created more than one address for what was meant to be one logical object. Using the canonical bump gives your protocol one predictable address per seed schema.

Study the official derivation explanation now. The implementation details will become hands-on in the next lesson, but understanding the model here will make the code much less mysterious.

PDA Derivation | Solana

Read the official Solana documentation’s explanation of why PDAs are off-curve, how seeds organize a program’s address space, and why the canonical bump is a security and consistency convention.

In Background, read the off curve rationale. Compare its PDA-versus-keypair table with the distinction made in this lesson. Then read Optional Seeds and Bump Seed, especially the bump discussion. Do not try to memorize the exact hashing procedure yet; focus on why the canonical bump produces one unambiguous expected address. Finally, in Common Seed Patterns, read the table and the adjacent collision warning, beginning with the seed patterns. Stop before the SDK code examples; you will use those APIs in the next module.


What “the program signs” actually means

It is common to hear that “a PDA can sign.” This is useful shorthand, but it can lead to the wrong mental model.

A PDA does not sign an outer transaction. It has no private key, so it cannot produce an Ed25519 signature. The transaction still needs a fee payer and must be submitted by some externally controlled wallet or service.

Instead, a program can request PDA signer privileges inside a CPI by using invoke_signed.

During that CPI, the runtime checks that:

  1. The currently executing program supplied the seed values and bump.
  2. Those inputs derive the PDA passed to the instruction.
  3. The PDA was derived using the ID of the currently executing program.

If those checks succeed, the runtime temporarily treats that PDA as a signer for the nested instruction. An inner program, such as the System Program or SPL Token Program, can then accept the PDA as an authority.

This is not a cryptographic signature generated by your Rust code. It is a runtime-enforced authorization rule: this program is entitled to act for this particular PDA because the PDA is derived from this program ID and these exact seeds.

This leads to an important boundary:

  • Your program can use invoke_signed for its own PDAs.
  • Your program cannot use invoke_signed to impersonate a user wallet.
  • Your program cannot use invoke_signed to sign for a PDA derived under another program’s ID.
  • A malicious caller cannot claim a random account is your PDA if your program re-derives and validates the expected address.

The previous lesson’s user-funded SOL transfer used ordinary invoke. The user’s outer transaction signature was propagated into the CPI. A future PDA-funded transfer will use invoke_signed, where Solana grants signer privilege to a PDA for that inner invocation.


PDA address, account ownership, and authority are different concepts

“Program-controlled account” can hide several separate ideas. Keeping them distinct will prevent many design and security mistakes.

ConceptWhat it answersExample
AddressWhich public key identifies this account?A PDA derived from "profile" and a user public key
Account ownerWhich program may modify this account’s data?Your program owns the profile data account
Signer privilegeWhich account authorized this instruction?A user wallet in the outer transaction, or a PDA during a CPI
Token authorityWho may authorize an SPL Token operation?A PDA configured as a token account’s authority

A PDA is only an address derivation scheme. Deriving one does not create an on-chain account, allocate data space, deposit rent-exempt lamports, or assign an account owner.

Creating an account at a PDA address is a separate operation, normally performed through a System Program CPI. Your program commonly uses invoke_signed because the new PDA address must satisfy a signer requirement during account creation.

Once created, that PDA-addressed account may be used in different ways:

  • A state account may be owned by your program, allowing your program to serialize and update its data.
  • A token account is owned by the SPL Token Program, but its transfer authority can be a PDA controlled by your program.
  • A System Program-owned PDA account can hold SOL in designs where the PDA is used as a System Program authority.
  • A PDA may be used only as an authority identifier, without itself holding your application data.

The distinction is especially relevant for SPL tokens. A token vault’s on-chain data belongs to the Token Program, not to your application program. Your program controls the vault’s behavior because the Token Program recognizes the PDA as its configured authority, and your program can invoke the Token Program with that PDA signer privilege.


A concrete escrow authority model

Imagine a future token escrow program with an escrow PDA derived from:

  • a fixed seed such as "escrow",
  • the order creator’s public key,
  • an order identifier.

The PDA can serve as the authority over a token vault. The program’s release instruction would still require explicit rules, for example:

  1. Load and validate the escrow state account.
  2. Confirm that the supplied vault and escrow authority match the expected PDA derivation.
  3. Check that the order is active and has not already been settled.
  4. Verify whichever user authorization or deadline condition the protocol requires.
  5. Invoke the Token Program to transfer tokens, with the PDA authorized through invoke_signed.
  6. Mark the escrow as settled so the transfer cannot be repeated.

The PDA does not decide when to release assets. It merely gives the program a controlled authority that the program can use after enforcing the protocol rules.

This is why a PDA is closer to a locked protocol role than to an autonomous agent. Someone still submits a transaction and pays its fee; the program evaluates the request; the runtime grants the PDA signer privilege only for the justified nested operation.


Seed design is part of your protocol interface

Because clients and programs must derive the same addresses, seed design is not an internal implementation detail. Treat it as part of the protocol’s public interface.

A robust seed scheme usually includes:

  • A fixed, descriptive prefix such as "config", "profile", or "vault" to separate account categories.
  • Stable identifiers, commonly public keys or fixed-width numeric IDs.
  • Explicit byte encodings for numbers and strings.
  • A documented canonical bump policy.
  • Program-side validation that every supplied PDA matches the intended seeds.

Be careful about ambiguity. Seed inputs are concatenated during derivation, so differently grouped inputs can represent the same byte sequence. The official documentation’s "ab" plus "cd" example illustrates why fixed-length encodings or an unambiguous separator are useful.

Also avoid making a user-controlled string the only thing that determines a privileged PDA. If a PDA represents a global treasury, its seed should be a fixed protocol constant, not a caller-selected label. If it represents a per-user record, include the user’s public key and require the appropriate signer when the record is created or changed.

Finally, remember that redeploying a program under a different program ID creates a different PDA namespace. The same seeds will no longer derive the same addresses. That is one reason program upgrades and state migrations require careful planning later in the course.


Key takeaways

  • A Program Derived Address is a deterministic address derived from seeds, a program ID, and a canonical bump.
  • PDAs are deliberately off-curve, so no private key exists and no external wallet can sign for them.
  • A program can authorize its own PDA during a CPI with invoke_signed; this is runtime authorization, not a private-key signature.
  • PDAs make predictable program state, escrow authorities, token vault authorities, and protocol configuration possible without keypair management.
  • A PDA is an address, not automatically an existing account. Account creation, account ownership, signer privilege, and token authority are separate concepts.
  • PDAs do not replace application authorization. Your program must still validate users, state, recipients, seed-derived addresses, and protocol conditions before moving assets.

Next, you will derive PDAs directly from seeds and a program ID, inspect the bump seed in practice, and begin using deterministic addresses as real program inputs.

Can't find a good explanation? Sign up and we'll make it for you

Sign up