Luau Snippets

Luau is Roblox's version of Lua 5.1 with gradual typing, better performance, and a richer standard library. These snippets cover patterns that show up in nearly every experience. Copy them, change the variable names, stop rewriting the same stuff from scratch.

DataStore: keep player progress between sessions

DataStoreService saves data so players do not lose their stuff when they disconnect. Every call can fail — network hiccups, Roblox throttling, you name it. Always wrap reads and writes in pcall. Use SetAsync for simple writes and UpdateAsync when you need to read-modify-write atomically.

local DataStoreService = game:GetService("DataStoreService")
local store = DataStoreService:GetDataStore("PlayerData")

local function load(player)
  local ok, data = pcall(function()
    return store:GetAsync(player.UserId)
  end)
  if not ok then
    warn("Load failed for " .. player.Name .. ":", data)
    return nil
  end
  return data
end

local function save(player, data)
  local ok, err = pcall(function()
    store:SetAsync(player.UserId, data)
  end)
  if not ok then
    warn("Save failed for " .. player.Name .. ":", err)
  end
end

game.Players.PlayerAdded:Connect(function(player)
  local data = load(player) or { coins = 0, level = 1 }
  -- attach data to player for use in other scripts
end)

game.Players.PlayerRemoving:Connect(function(player)
  save(player, { coins = 50, level = 3 })
end)

TweenService: animate without keyframes

TweenService animates any numeric property over time. Doors, moving platforms, UI transitions, camera pans — it handles all of them. Much simpler than the Animation Editor and works on parts, GUIs, and lighting. The easing style and direction control how things accelerate.

local TweenService = game:GetService("TweenService")

local function movePart(part, targetPos, duration)
  local info = TweenInfo.new(
    duration,                       -- seconds
    Enum.EasingStyle.Quad,          -- acceleration curve
    Enum.EasingDirection.Out,       -- ease out (fast start, slow end)
    0,                              -- repeat count (0 = once)
    false,                          -- reverse after finishing
    0                               -- delay before starting
  )
  local goal = { Position = targetPos }
  local tween = TweenService:Create(part, info, goal)
  tween:Play()
  return tween
end

-- Usage:
local door = workspace.Building.Door
movePart(door, door.Position + Vector3.new(0, 12, 0), 0.8)

Raycasting: line-of-sight and ground checks

Shoots a straight line and checks what it hits. Gun hit detection, enemy line-of-sight, finding the floor under a character, measuring distance through obstacles. Always pass a RaycastParams to exclude the origin object and set filter behavior explicitly.

local origin = character.Head.Position
local direction = character.Head.CFrame.LookVector * 100

local params = RaycastParams.new()
params.FilterDescendantsInstances = { character }
params.FilterType = Enum.RaycastFilterType.Exclude

local result = workspace:Raycast(origin, direction, params)
if result then
  local hitPart = result.Instance
  local hitPos = result.Position
  local hitNormal = result.Normal
  local hitMaterial = result.Material

  print("Hit:", hitPart:GetFullName())
  print("At distance:", (origin - hitPos).Magnitude, "studs")
end

RemoteEvents: client-server messaging

RemoteEvents are how LocalScripts talk to server Scripts and back. Client fires a request, server listens and responds. This is the backbone of multiplayer: shooting, buying, opening doors, sending chat. One rule: never trust the client. Validate every argument on the server.

-- Server Script (in ServerScriptService)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remote = ReplicatedStorage:WaitForChild("BuyItem")

remote.OnServerEvent:Connect(function(player, itemId)
  -- Validate: does the player have enough coins?
  -- Validate: does the item exist?
  -- Validate: is itemId a number? (never trust the client)
  if typeof(itemId) ~= "number" then return end

  print(player.Name .. " wants to buy item " .. itemId)
  -- grant item, deduct coins, etc.
end)

-- Client LocalScript (in StarterPlayerScripts)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remote = ReplicatedStorage:WaitForChild("BuyItem")

-- Fire when the player clicks a Buy button
remote:FireServer(14)

ModuleScripts: share code without copy-paste

ModuleScripts are Luau's version of a module. Put shared logic in one and require() it from any other script. Keeps your codebase organized and stops you from pasting the same utility functions across twenty files. A ModuleScript returns a table — everything you want to share goes in it.

-- ModuleScript in ServerStorage named "MathUtils"
local MathUtils = {}

function MathUtils.clamp(value, min, max)
  return math.max(min, math.min(max, value))
end

function MathUtils.lerp(a, b, t)
  return a + (b - a) * t
end

function MathUtils.distance(a, b)
  return (a - b).Magnitude
end

return MathUtils

-- Usage from any Script:
local MathUtils = require(game.ServerStorage.MathUtils)
local speed = MathUtils.clamp(playerSpeed, 0, 100)

Production tip: Always wrap DataStore operations in pcall. Roblox's cloud infrastructure occasionally throttles or rejects requests, especially during high-traffic events. A single uncaught error kills the entire script. Use exponential backoff on retry: wait 1 second, then 2, then 4 before giving up.

New to scripting? The Getting Started guide walks you through your first script step by step. For plugins and shortcuts that speed up your coding, check Studio Tips.