Save slots

How slots are named, laid out on disk, listed cheaply and moved between machines with export and adopt.

Get started NexusForge Persistence 0.2.0 Updated

A slot is a directory#

Every slot is a directory under the save root, with its own primary file, its own backups and its own revision sequence:

text
Application.persistentDataPath/
  nexusforge/<product namespace>/<environment>/
    slots/
      default/primary.nfsav
      slot-03/primary.nfsav
      autosave/primary.nfsav
      checkpoint-0001/primary.nfsav

Because a slot owns its backups, a bad write in one slot can never cost you another one.

Naming rules#

A slot name must be safe as a path segment, so SaveSlotId applies one rule to every identifier in the package:

text
^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$

That single rule removes path traversal, Windows device-name collisions, trailing-dot aliasing and case-sensitivity differences between platforms. Slot ids are also capped by Limits.MaxIdentifierLength (64 by default).

csharp
var slot = new SaveSlotId(class="tok-str">"slot-03");                  // throws if the name is unsafe

if (!SaveSlotId.TryCreate(playerTypedName, out var fromInput))
{
    ShowErrorToPlayer(class="tok-str">"That name cannot be used for a save slot.");
}

Use TryCreate whenever the name originates outside your code.

Listing slots without reading saves#

A "Continue" menu should cost kilobytes, not megabytes, so listings read the header and metadata only:

csharp
var slots = await NexusForgePersistence.Slots.ListAsync();
var info  = await NexusForgePersistence.Slots.InfoAsync(new SaveSlotId(class="tok-str">"slot-03"));

foreach (var descriptor in slots.Value)
{
    AddRow(descriptor.Slot, descriptor.Metadata.ModifiedUtc, descriptor.BackupCount);
}

Metadata can include your own display values (a chapter name, a playtime, a level), which is what makes a slot list readable without decrypting anything.

Moving a save between machines#

csharp
var exported = await NexusForgePersistence.Slots.ExportAsync(slot, destinationPath);

var adopted = await NexusForgePersistence.Slots.AdoptAsync(sourcePath, slot);

AdoptAsync validates the file before accepting it, so importing cannot drop an unverified or foreign file into your save root. Both calls go through the same integrity and envelope checks a load would.

Deleting#

csharp
await NexusForgePersistence.Slots.DeleteAsync(slot);

Deletion is explicit and permanent for that slot. The framework never deletes a slot on its own — not on shutdown, not on disposal, not on reset. Disposal only stops work.

Next#

Something wrong on this page? Every page here describes behaviour that is checked in the repository. If a page and the package disagree, the package wins.

Report a documentation problem · Frequently asked questions · Troubleshooting