---
title: "6. Vault and Resource Patterns"
url: "https://radix.wiki/developers/scrypto/06-vault-patterns"
version: "1.4.1"
updated: 2026-07-27
last_verified: 2026-07-27
license: CC-BY-4.0
license_url: "https://creativecommons.org/licenses/by/4.0/"
---

# 6. Vault and Resource Patterns

## Introduction

Radix enforces a strict invariant: every [resource](/contents/tech/core-concepts/asset-oriented-programming) must exist inside a container at all times. There are two container types: **[Vaults](https://docs.radixdlt.com/docs/buckets-and-vaults)** (permanent, on-ledger storage) and **[Buckets](https://docs.radixdlt.com/docs/resources)** (temporary, transaction-scoped carriers). The [Radix Engine](/contents/tech/core-protocols/radix-engine) guarantees that resources cannot be duplicated, accidentally destroyed, or left in limbo – if your transaction ends with an undeposited bucket, it fails. This "physical resource" model eliminates entire categories of bugs common in other smart contract platforms.

## Vault Patterns

### Single-Vault Component

The simplest pattern: a component holds one vault to store a single resource type. A token sale component, for example, stores tokens in a vault and returns XRD payment to the buyer's account.

```
struct TokenSale {
    token_vault: Vault,    // holds tokens for sale
    xrd_vault: Vault,      // collects XRD payments
    price: Decimal,
}
```

### Multi-Vault Component (HashMap)

When a component needs to manage arbitrary resource types (e.g. a DEX liquidity pool or a wallet-like component), use a `HashMap`. When a new resource type is deposited, create a new vault; when an existing type arrives, deposit into the matching vault.

```
struct MultiVault {
    vaults: HashMap,
}

impl MultiVault {
    pub fn deposit(&mut self, bucket: Bucket) {
        let addr = bucket.resource_address();
        self.vaults
            .entry(addr)
            .or_insert_with(|| Vault::new(addr))
            .put(bucket);
    }
}
```

### Vault Take & Put

Withdraw resources from a vault with `.take(amount)` (returns a Bucket) or `.take_all()`. Deposit with `.put(bucket)`. For non-fungibles, use `.take_non_fungible(&id)` or `.take_non_fungibles(&ids)` to withdraw specific items.

## Bucket Patterns

### Bucket Passing (Move Semantics)

[Buckets](https://docs.radixdlt.com/docs/resources) use Rust's ownership model – passing a bucket to a function _moves_ it. The caller no longer has access. This prevents double-spending at the language level:

```
// Caller creates a bucket, passes it to the component
let payment: Bucket = account.withdraw(xrd_address, dec!("100"));
let tokens: Bucket = sale_component.buy(payment);
// 'payment' is now consumed — cannot be used again
account.deposit(tokens);
```

### Bucket Splitting

Use `.take(amount)` on a bucket to split it into two buckets – the original retains the remainder. This is how you implement partial fills, fee extraction, or distributing resources across multiple destinations within a single transaction.

### The Worktop

In [transaction manifests](/contents/tech/core-protocols/transaction-manifests), returned resources land on the **worktop** – a temporary staging area. Use `TAKE_FROM_WORKTOP` to create named buckets from worktop resources, then pass them to subsequent method calls. The transaction fails if any resources remain on the worktop at the end.

## Next Steps

- [Multi-Component Architecture](/developers/scrypto/07-multi-component-architecture) – split a growing dApp across components that call each other

## External Links

- [Vaults and Buckets – Official Docs](https://docs.radixdlt.com/docs/buckets-and-vaults)
- [Resources – Official Docs](https://docs.radixdlt.com/docs/resources)
- Regulated Token Example – Official Docs
