Sift Roblox documentation: Setup Guide & API Patterns - Platform

Sift Roblox documentation: Setup Guide & API Patterns

Learn how to install Sift for Roblox development, work with immutable Luau data, use Dictionary patterns, and organize reliable project code.

2026-08-20
Sift Roblox Wiki Team
Quick Guide
  • Sift Roblox documentation explains immutable data patterns for Luau projects.
  • Wally installation adds Sift through a Roblox-focused package workflow.
  • TypeScript support keeps the API familiar for roblox-ts developers.
  • Immutable updates return new values instead of changing the original table.
  • Maintenance note: Verify the repository status before starting a new production dependency.

Sift Roblox Documentation Overview

Sift is an immutable data library designed for Luau and Roblox development. Instead of changing a table directly, an immutable utility creates and returns an updated value. This approach can make state changes easier to trace, especially in systems that manage player data, UI state, inventories, or replicated configuration.

The library is closely associated with dictionary and collection operations. Its design is heavily influenced by Llama, while its implementation uses native Luau types rather than relying on runtime type-checking. That distinction matters when building a project: static typing and validation are separate concerns, so teams should decide how they want to validate incoming data.

A useful starting point is the Sift repository on GitHub. It contains installation notes, release information, examples, and links toward generated documentation.

Core Principle

Treat each data transformation as a new value. Keep the previous table available when debugging, comparing state, or calculating a rollback.

What Sift Is Best Suited For

Sift is most useful when your code repeatedly transforms structured data without wanting every system to mutate the same table reference. Common examples include:

  • Building a new player profile from several data sources.
  • Merging default settings with saved preferences.
  • Removing entries without calling table.remove or assigning nil manually.
  • Updating UI state in a predictable way.
  • Sharing collection helpers between Luau and roblox-ts codebases.
Use CaseWhy Immutable Operations HelpRecommended Starting Point
Player profilesReduces accidental changes across systemsDictionary operations
UI stateMakes state transitions easier to compareSmall focused updates
Inventory dataKeeps transformations explicitDictionary and array helpers
ConfigurationSupports layered defaults and overridesDictionary.merge
Shared TypeScript codePreserves a familiar API style@rbxts/sift

Important Project Context

The library is an open-source utility rather than a Roblox experience or gameplay system. It does not provide maps, characters, combat mechanics, quests, or progression features. Its role is to help developers structure and transform data inside Roblox projects.

The repository identifies Sift as MIT-licensed and provides multiple distribution paths. However, its current maintenance status should be reviewed before adoption. A team may choose to pin a known version, inspect the source, or maintain a fork if long-term support is required.

Installation and Project Setup

Sift can be added to a Roblox project through Wally, roblox-ts, or a manual workflow. Select one route and keep the dependency layout consistent across your team. Mixing installation methods without a clear reason can make version tracking and deployment harder.

Check the Version First

Before installing, confirm the version used by your project and lock it where possible. Avoid copying a floating placeholder into production configuration without checking the available release.

Installation Route Comparison

WorkflowPackage ReferenceBest ForMain Consideration
Wallycsqrl/sift@x.x.xLuau projects using WallyReplace the placeholder with a selected version
roblox-ts@rbxts/siftTypeScript projectsInstall through the project’s npm workflow
Creator StoreSift modelStudio-focused setupReview the inserted hierarchy before use
GitHub releaseRepository release filesManual control or inspectionMaintain your own version record

Wally Setup

For a Wally-based project, add Sift as a dependency in wally.toml:

[dependencies]
Sift = "csqrl/sift@x.x.x"

Replace x.x.x with the version selected for your project. Then run:

wally install

After installation, confirm that the package appears in the expected location and that your project’s Rojo mapping includes the dependency path. The exact folder layout depends on your project template, so verify the generated tree rather than assuming every repository uses the same structure.

roblox-ts Setup

Sift includes TypeScript compatibility with an API intended to match its Luau counterpart. A roblox-ts project can install the package with:

npm install @rbxts/sift

A simple dictionary merge can look like this:

import { Dictionary, Sift } from "@rbxts/sift"

const result = Dictionary.merge(
  { a: 1, c: 2 },
  { b: 3, c: Sift.None }
)

The important behavior is that the result is a new dictionary. The original inputs remain separate values. Confirm your compiler configuration and package version before relying on a particular type export.

1

Choose the Dependency Route

Decide whether your project will use Wally, roblox-ts, a Creator Store model, or a manually managed release. Document that decision in the project README.

2

Pin and Install the Package

Select a known version, add the dependency, and run the matching installation command. Keep the lockfile or version record under source control.

3

Verify the Import Path

Open a small test module and import the collection utility you plan to use. Resolve package mapping problems before integrating Sift into larger systems.

4

Run a Focused Test

Merge two small dictionaries, confirm the expected result, and check that the original inputs were not changed.

Immutable Dictionary Patterns

Dictionary operations are the most practical entry point for many Roblox systems. A dictionary is a key-value table, such as a profile containing currency, settings, and unlocked content. With immutable updates, each operation produces a replacement value instead of modifying the shared table in place.

Recommended State Pattern

Keep the current state in one variable, calculate the next state with Sift, and replace the reference only after the transformation succeeds.

Common Transformation Goals

GoalSift PatternExpected Result
Combine valuesDictionary.mergeA new dictionary containing selected keys
Remove a valueUse the library’s removal helperA new dictionary without the selected entry
Apply a targeted updateUse a dictionary update helperOnly the intended key changes
Represent deletionSift.None in supported operationsThe selected key is omitted from the merged result
Preserve input dataAvoid direct assignment to the source tablePrevious state remains available

The Sift.None marker is especially useful in merge-style code. In the documented example, merging { a: 1, c: 2 } with { b: 3, c: Sift.None } produces { a: 1, b: 3 }. This communicates deletion as part of the transformation rather than mixing deletion logic into a separate mutation step.

const base = {
  displayName: "Builder",
  soundEnabled: true,
  tutorialSeen: true
}

const next = Dictionary.merge(base, {
  soundEnabled: false,
  tutorialSeen: Sift.None
})

The example demonstrates two useful ideas: a normal replacement for soundEnabled, and an explicit removal for tutorialSeen. Always test the exact helper behavior against the version installed by your project, particularly when migrating from another immutable library.

Why Input Preservation Matters

Direct mutation can create hidden coupling:

profile.Coins += 50

Any system holding the same table reference can observe that change immediately. That may be acceptable in a small script, but it becomes harder to reason about when profile data is shared by saving, UI, analytics, and gameplay systems.

An immutable approach makes the transition more deliberate:

local updatedProfile = Dictionary.merge(profile, {
    Coins = profile.Coins + 50,
})

The exact module import depends on your project structure. The key practice is to calculate updatedProfile as a new value and then pass it to the systems that need the updated state.

Keep Transformations Small

Avoid creating one large transformation that changes unrelated parts of a profile. Smaller operations are easier to test and review:

  • Update currency separately from settings.
  • Merge server defaults before applying player preferences.
  • Remove temporary fields before saving.
  • Keep UI-only state outside persistent profile data.
  • Name intermediate values when a transformation has several stages.

Luau and roblox-ts Workflow Comparison

Sift is intended to support both Luau and roblox-ts workflows. The conceptual API is designed to remain similar, but the surrounding tooling is different. Luau projects commonly use Wally and Rojo, while roblox-ts projects use npm and TypeScript compilation.

Type Safety Is Not Runtime Validation

Native Luau types and TypeScript declarations help during development, but they do not automatically validate data received from players, persistence services, or external boundaries.

Luau Projects

Use Wally for dependency management, Rojo for synchronization when needed, and focused module tests for collection transformations.

roblox-ts Projects

Install @rbxts/sift, use the typed API, and keep package versions aligned with the TypeScript compiler configuration.

Validation Layer

Add a separate validation library or project-specific checks when data crosses a trust boundary or enters persistent storage.

Choosing Between Luau and TypeScript

Project ProfileBetter FitSift Consideration
Existing Luau codebaseLuau packageKeep imports and package mappings simple
Typed team workflowroblox-tsUse the built-in TypeScript compatibility
Mixed repositoryShared conventionsDocument which layer owns each transformation
Untrusted inputEither languageAdd runtime validation separately
Long-term maintenancePinned dependencyRecord the selected version and review project health

Testing Immutable Behavior

A useful test should verify both the result and the original input:

local original = {
    Coins = 100,
    Rank = 2,
}

local updated = Dictionary.merge(original, {
    Coins = 150,
})

assert(updated.Coins == 150)
assert(original.Coins == 100)

This test is intentionally small. It confirms the property that matters most: the updated value contains the new data while the original remains unchanged. Expand the test suite for nested dictionaries, missing keys, deletion markers, and arrays used by your application.

Maintenance, Compatibility, and Best Practices

A dependency is part of your project’s technical surface area. Before using Sift in a new production system, review its repository activity, release history, license, package availability, and compatibility with your current Roblox toolchain.

Plan for Dependency Ownership

If a library is no longer actively maintained, pin the version, archive the documentation you depend on, and decide whether your team will fork or replace it if a future toolchain change causes problems.

Dependency Review Checklist

Before Adding Sift:

  • Confirm the selected package version and installation route
  • Test dictionary merge and deletion behavior in the current project
  • Check Luau, roblox-ts, Wally, Rojo, and compiler compatibility
  • Add runtime validation for untrusted or persistent data
  • Record a fallback plan if maintenance or compatibility changes

Practical Engineering Rules

  1. Do not mutate shared state accidentally. Treat profile and configuration tables as values that should be replaced deliberately.
  2. Keep package boundaries clear. A utility library should transform data, while persistence and networking systems should own their respective responsibilities.
  3. Validate at boundaries. Static types cannot guarantee that saved data or remote input has the expected shape.
  4. Prefer explicit intermediate values. Names such as mergedDefaults, playerSettings, and nextProfile make transformations easier to inspect.
  5. Test deletion behavior. A missing key, a nil value, and Sift.None may have different meanings in a merge operation.
  6. Document the chosen version. This is especially important when the project may be maintained by contributors who did not select the original dependency.

Suggested Documentation Layout

Documentation PageInclude
InstallationPackage route, version, commands, folder mapping
API NotesHelpers used by the project and short examples
State ConventionsWhich tables are immutable and who owns replacements
ValidationRuntime checks for saved and remote data
Upgrade PlanCompatibility tests, dependency review, fallback option

The generated documentation linked from the project ecosystem can help with exact signatures, while the repository remains the best place to review source, releases, and licensing information. Avoid copying examples without checking whether their syntax matches the version installed in your project.

Sift Roblox Documentation FAQ

Fast Reference

Start with one dictionary transformation, test the unchanged input, and expand into larger state systems only after the behavior is clear.

Q: What is Sift used for in Roblox development?

Sift is an immutable data library for Luau and roblox-ts. It helps developers create updated dictionaries, arrays, and collection values without directly mutating the original table.

Q: How can I install Sift in a Roblox project?

The documented routes include Wally, the roblox-ts package named @rbxts/sift, a Roblox Creator Store model, and GitHub release files. Choose one route and record the version used by the project.

Q: What does Sift.None do?

In supported merge operations, Sift.None represents removal of a key. For example, merging a dictionary with c set to Sift.None can produce a result where c is omitted.

Q: Does Sift replace runtime data validation?

No. Native Luau types and TypeScript typings support development-time checks, but teams should add a separate validation layer for remote input, saved data, and other untrusted boundaries.