---
title: PDA Accounts
description:
  Create onchain accounts at Solana PDA addresses using invoke_signed and
  Anchor's init constraint. invoke_signed verification flow and Anchor PDA
  creation patterns with code examples.
url: /docs/core/pda/pda-accounts
type: tutorial
prerequisites:
  - /docs/core/pda
  - /docs/core/pda/pda-derivation
  - /docs/core/cpi
related:
  - /docs/core/cpi/cpi-with-pda
  - /docs/core/accounts/account-types
  - /docs/core/programs/program-deployment
---

{/* TOC: PDA Signing via invoke_signed, Create a PDA Account */}

<Callout type="info" title="Summary">
  Create PDA accounts via _rs`invoke_signed`_ with the PDA's seeds. Only the
  owning program can sign for a PDA. Anchor's _rs`init`_ constraint automates
  PDA account creation.
</Callout>

## PDA Signing via `invoke_signed`

When a program needs to sign on behalf of a PDA during a CPI, it uses
_rs`invoke_signed`_ with the PDA's seeds. The runtime verifies the seeds derive
the expected PDA using the **calling program's ID**, ensuring only the owning
program can sign. For the full verification flow, see
[PDA Signing](/docs/core/cpi/cpi-cost-model#pda-signing).

## Create a PDA Account

Deriving a PDA and creating an account at a PDA are separate operations. You
must explicitly create the account after deriving the address.

To create an account at a PDA, the deriving program invokes the System Program's
_rs`create_account`_ instruction via [`invoke_signed`](/docs/core/cpi), passing
the PDA's seeds so the runtime can verify the program's authority over that
address.

<WithMentions>

The example below uses the [Anchor framework](https://www.anchor-lang.com/docs)
to create a new account with a program-derived address. The program includes a
single [`initialize`](mention:initialize) instruction to create the new account,
which will store the [user address](mention:user-address) and
[bump seed](mention:bump) used to derive the PDA.

```rs title="Program"
use anchor_lang::prelude::*;

declare_id!("75GJVCJNhaukaa2vCCqhreY31gaphv7XTScBChmr1ueR");

#[program]
pub mod pda_account {
    use super::*;

    // !mention initialize
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let account_data = &mut ctx.accounts.pda_account;
        // store the address of the `user`
        // !mark
        // !mention user-address
        account_data.user = *ctx.accounts.user.key;
        // store the canonical bump
        // !mark
        // !mention bump
        account_data.bump = ctx.bumps.pda_account;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    // !mention user-address
    pub user: Signer<'info>,

    #[account(
        init,
        // define the seeds to derive the PDA
        // !mark
        // !mention user-address
        seeds = [b"data", user.key().as_ref()],
        // use the canonical bump
        // !mark
        // !mention bump
        bump,
        payer = user,
        space = 8 + DataAccount::INIT_SPACE // 8 bytes for Anchor account discriminator
    )]
    pub pda_account: Account<'info, DataAccount>,
    pub system_program: Program<'info, System>,
}

#[account]
#[derive(InitSpace)]
pub struct DataAccount {
    // !mark
    // !mention user-address
    pub user: Pubkey,
    // !mark
    // !mention bump
    pub bump: u8,
}
```

</WithMentions>

<WithMentions>

The [`init`](mention:init) constraint tells Anchor to
[invoke the System Program](/docs/core/programs/builtin-programs#the-system-program)
to create a new account using the PDA as the address. The [seeds](mention:seeds)
used to create the PDA are:

- The fixed string: "data"
- The address of the user account provided in the instruction
- The canonical [bump seed](mention:bump)

In this example, the bump constraint is not assigned a value, so Anchor will use
_rs`find_program_address`_ to derive the PDA and find the bump.

```rust title="pda_account"
#[account(
    // !mention init
    init,
    // !mention seeds
    seeds = [b"data", user.key().as_ref()],
    // !mention bump
    bump,
    payer = user,
    space = 8 + DataAccount::INIT_SPACE // 8 bytes for Anchor account discriminator
)]
pub pda_account: Account<'info, DataAccount>,
```

</WithMentions>

<WithMentions>

The test file below contains a transaction that invokes the
[`initialize`](mention:initialize) instruction to create a new account with a
program-derived address. The file contains code to
[derive the PDA](mention:pda).

The example also shows how to [fetch](mention:fetch) the new account that will
be created.

```ts title="Test"
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { PdaAccount } from "../target/types/pda_account";
import { PublicKey } from "@solana/web3.js";

describe("pda-account", () => {
  const provider = anchor.AnchorProvider.env();
  anchor.setProvider(provider);

  const program = anchor.workspace.PdaAccount as Program<PdaAccount>;
  const user = provider.wallet as anchor.Wallet;

  // !mention(1:5) pda
  // Derive the PDA address using the seeds specified on the program
  const [PDA] = PublicKey.findProgramAddressSync(
    [Buffer.from("data"), user.publicKey.toBuffer()],
    program.programId
  );

  it("Is initialized!", async () => {
    const transactionSignature = await program.methods
      // !mention initialize
      .initialize()
      .accounts({
        user: user.publicKey
      })
      .rpc();

    console.log("Transaction Signature:", transactionSignature);
  });

  it("Fetch Account", async () => {
    // !mention fetch
    const pdaAccount = await program.account.dataAccount.fetch(PDA);
    console.log(JSON.stringify(pdaAccount, null, 2));
  });
});
```

</WithMentions>

<Callout type="warn">
  If you invoke the `initialize` instruction again with the same `user` address
  seed, the transaction will fail. This happens because an account already
  exists at the derived address.
</Callout>
