> For the complete Mojo documentation index, see [llms.txt](/llms.txt).
> Markdown versions of all pages are available by appending .md to any URL (e.g. /docs/manual/basics.md).

# @explicit_destroy

The `@explicit_destroy` decorator disables automatic destruction via the
`__del__()` method and requires explicit cleanup through named destructor
methods. When applying this decorator, you must call a named destructor
method to consume the value. If you don't, the compiler emits an error.

Use explicit destruction when cleanup must be performed deliberately, may
fail and require error handling, or your type offers multiple valid ways to end
a value's lifetime (such as saving to file and closing the file descriptor, or
quitting without saving).

## Implicit vs. explicit destruction

Mojo supports two destruction models. Most types rely on compiler-managed
lifetime analysis, while some types opt into explicit control for stronger
cleanup guarantees.

_Implicit destruction_ (the default): The compiler automatically calls
`__del__()` when a value has no further uses. Cleanup is triggered by Mojo's
lifetime analysis and requires no manual intervention. You may override
`__del__()` in your type, but the compiler does not verify that cleanup is
performed intentionally.

_Explicit destruction_: You intentionally call named destructor methods
(such as `cleanup()` or `save_and_close()`). The compiler disables automatic
destruction and enforces explicit consumption. Failing to call a destructor
before a value leaves scope results in a compile-time error.

Most types use implicit destruction. Explicit destruction adds a layer of
safety when cleanup may fail, requires error handling, or benefits from
deliberate control over how a value's lifetime ends.

## Basic usage

To opt into explicit, compiler-enforced destruction, mark types with
`@explicit_destroy` and provide named destructor methods that use the
`deinit self` argument convention:

```mojo
@explicit_destroy
struct FileBuffer:
    var path: String
    var data: String

    def __init__(out self, path: String):
        self.path = path
        self.data = ""

    def write(mut self, content: String):
        self.data += content

    def save_and_close(deinit self) raises:
        write_to_disk(self.path, self.data)
```

Declaring `@explicit_destroy` requires you to add intentional calls to
type-specific destructors before the end of scope:

```mojo
def write_log(path: String, message: String) raises:
    var buffer = FileBuffer(path)
    buffer.write(message)
    buffer^.save_and_close()  # Required before `buffer` leaves scope
```

If you omit this call, the compiler emits an error.

## Custom error messages

To improve compiler diagnostics for explicit destruction, include a
custom error message with the decorator:

```mojo
@explicit_destroy("Must call save_and_close() or discard()")
struct FileBuffer:
    def save_and_close(deinit self) raises:
        write_to_disk(self.path, self.data) # Store data

    def discard(deinit self):
        pass  # Abandon without writing
```

## Related

- [Death of a value](/docs/manual/lifecycle/death/) - Complete coverage of value
  destruction and lifetime management
- [`AnyType`](/docs/std/builtin/anytype/AnyType/) - Base trait for all types
- [`ImplicitlyDestructible`](/docs/std/builtin/anytype/ImplicitlyDestructible/)
  - Trait for automatically destructible types
