---
title: "2. Resources, Vaults, and NFTs"
url: "https://radix-wiki.miow.me/developers/scrypto/02-resources-and-nfts"
updated: 2026-10-03
description: "A resource is any digital asset on Radix – tokens, NFTs, badges, LP tokens, etc. Unlike Solidity where tokens are contract state, Radix resources are native…"
---

# 2. Resources, Vaults, and NFTs

## Resources

A [resource](https://docs.radixdlt.com/docs/resources) is any digital asset on Radix – tokens, [NFTs](https://en.wikipedia.org/wiki/Non-fungible_token), [badges](https://docs.radixdlt.com/docs/authorization-approach), LP tokens, etc. Unlike [Solidity](https://soliditylang.org) where tokens are contract state, Radix [resources](/contents/tech/core-concepts/resources) are native engine primitives with built-in rules for minting, burning, transferring, and access control.

There are two kinds:

- **Fungible** – identical, interchangeable units (e.g., [XRD](/contents/tech/core-protocols/xrd-token), stablecoins)
- **Non-fungible** – unique items with individual data (e.g., [NFTs](/contents/tech/core-protocols/nfts-on-radix), access [badges](https://docs.radixdlt.com/docs/user-badge-pattern))

### Creating Fungible Resources

```
let my_token: Bucket = ResourceBuilder::new_fungible(OwnerRole::None)
    .metadata(metadata!(
        init {
            "name" => "My Token", locked;
            "symbol" => "MYT", locked;
        }
    ))
    .mint_initial_supply(1_000_000)
    .into();
```

This creates 1 million tokens with locked name and symbol. The `: Bucket` annotation is required from [Scrypto v1.4.0](https://github.com/radixdlt/radixdlt-scrypto/releases/tag/v1.4.0): without it `.into()` has no target type, and the build stops with error E0282, type annotations needed, as soon as the variable is used. The `OwnerRole::None` means no one can change the resource's configuration after creation.

### Creating Non-Fungible Resources ([NFTs](https://en.wikipedia.org/wiki/Non-fungible_token))

```
#[derive(ScryptoSbor, NonFungibleData)]
pub struct Ticket {
    pub event_name: String,
    pub seat: u32,
    #[mutable]
    pub used: bool,
}

let tickets: Bucket = ResourceBuilder::new_integer_non_fungible::(OwnerRole::None)
    .metadata(metadata!(
        init {
            "name" => "Event Ticket", locked;
        }
    ))
    .mint_initial_supply([
        (IntegerNonFungibleLocalId::new(1), Ticket {
            event_name: "RadFest".into(),
            seat: 42,
            used: false,
        }),
    ])
    .into();
```

Fields marked `#[mutable]` can be updated later via the `[ResourceManager](https://docs.radixdlt.com/docs/resources)`. Immutable fields are fixed at mint time.

## Vaults and [Buckets](https://docs.radixdlt.com/docs/resources)

Resources must always be inside a **container**:

| Container | Lifetime | Purpose |
| --- | --- | --- |
| **[Vault](/contents/tech/core-concepts/buckets-proofs-and-vaults)** | Permanent (on-ledger state) | Store resources between transactions |
| **Bucket** | Transient (single transaction) | Move resources during a transaction |

The [Radix Engine](/contents/tech/core-protocols/radix-engine) enforces that **all [buckets](https://docs.radixdlt.com/docs/buckets-and-vaults) must be empty by the end of every transaction**. This guarantees no resources are accidentally lost or left in limbo.

```
// Take 10 tokens from a vault into a bucket
let bucket: Bucket = self.my_vault.take(10);

// Put them into another vault
self.other_vault.put(bucket);
```

Typed variants (`FungibleVault`, `NonFungibleVault`, `FungibleBucket`, `NonFungibleBucket`) provide type-safe operations when you know the resource type at compile time.

## Proofs

[Proofs](https://docs.radixdlt.com/docs/auth) let you demonstrate ownership of a resource without transferring it – like showing an ID badge without handing it over.

```
// Create a proof of one admin badge held in a vault
let proof = self.admin_badge.as_fungible().create_proof_of_amount(1);

// A proof made in a blueprint comes back to you. Push it onto the
// Auth Zone, where the Radix Engine checks it against access rules
LocalAuthZone::push(proof);
```

A `Vault` has no `create_proof_of_all`: [fungible vaults](https://github.com/radixdlt/radixdlt-scrypto/blob/v1.4.0/scrypto/src/resource/vault.rs) prove an amount and non-fungible vaults prove specific IDs, and [`LocalAuthZone`](https://github.com/radixdlt/radixdlt-scrypto/blob/v1.4.0/scrypto/src/runtime/local_auth_zone.rs) is where a proof goes to count towards a call. `authorize_with_amount(1, || ...)` does both in one step and drops the proof when the closure returns.

Proofs are central to Radix's [authorization model](/developers/scrypto/03-authorization-and-badges). Protected methods check for proofs in the caller's [Auth Zone](/contents/tech/core-concepts/access-rules-and-auth-zones) rather than checking `msg.sender`.

## [ResourceManager](https://docs.radixdlt.com/docs/resources)

Every resource has a `[ResourceManager](https://docs.radixdlt.com/docs/resources)` – the on-ledger controller for that resource type. Use it to mint, burn, query supply, and update NFT data:

```
// Mint more tokens (if resource was created with mint role)
let new_tokens: Bucket = self.resource_manager.mint(500);

// Get total supply
let supply: Decimal = self.resource_manager.total_supply().unwrap();

// Update mutable NFT data
self.resource_manager.update_non_fungible_data(
    &nft_id,
    "used",
    true,
);
```

## Next Steps

- [Authorization and Access Rules](/developers/scrypto/03-authorization-and-badges) – decide who is allowed to mint, withdraw, and update what

## External Links

- [Resources documentation](https://docs.radixdlt.com/docs/resources)
- [Non-Fungible Tokens](https://docs.radixdlt.com/docs/learning-to-create-your-first-non-fungible)
- [Proofs and Authorization](https://docs.radixdlt.com/docs/auth)
- [What are Vaults and Buckets?](https://learn.radixdlt.com/article/what-are-vaults-and-buckets)
