
Roblox Core
- 52 installs
- 11 repo stars
- Updated August 3, 2026
- nonlooped/roblox-suite
Reference for Luau fundamentals and the Roblox service catalog: GetService patterns, data types, script locations, execution contexts, and the client-server data model.
About
Documents Luau fundamentals and the full Roblox service catalog including GetService patterns, data types, serialization, script locations, and the client-server data model. A Roblox developer loads it first so higher-level scripting skills rest on correct assumptions about types, authority, and where code can run.
- Universal Roblox scripting pattern via game:GetService and require
- Modern task library over deprecated wait/spawn/delay globals
Roblox Core by the numbers
- 52 all-time installs (skills.sh)
- +14 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #160 of 247 Game Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/nonlooped/roblox-suite --skill roblox-coreAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 52 |
|---|---|
| repo stars | ★ 11 |
| Last updated | August 3, 2026 |
| Repository | nonlooped/roblox-suite ↗ |
What it does
Reference for Luau fundamentals and the Roblox service catalog: GetService patterns, data types, script locations, execution contexts, and the client-server data model.
Files
roblox-core
Key sources: https://create.roblox.com/docs/en-us/scripting/services, https://create.roblox.com/docs/en-us/luau, https://create.roblox.com/docs/en-us/luau/tables, https://create.roblox.com/docs/en-us/luau/type-checking, https://create.roblox.com/docs/en-us/scripting/locations, https://create.roblox.com/docs/en-us/projects/data-model, https://create.roblox.com/docs/en-us/projects/client-server, https://create.roblox.com/docs/en-us/workspace/streaming, https://create.roblox.com/docs/en-us/scripting/multithreading, https://create.roblox.com/docs/en-us/scripting/attributes
Every other skill in this toolset assumes you understand the material here.
The Universal Roblox Scripting Pattern
1. local Service = game:GetService("ServiceName") — do this once, name the variable after the service. 2. local Module = require(ReplicatedStorage:WaitForChild("Module")) 3. Local helper functions. 4. Connect to events.
Services are the primary way you access engine functionality instead of a traditional standard library.
Modern Task Library
Use the modern task API; the legacy globals wait(), spawn(), and delay() are deprecated/soft-deprecated:
task.wait(n?)— yields for aboutnseconds (default one frame) and returns elapsed time.task.spawn(f, ...)— schedulesfto run asynchronously.task.defer(f, ...)— defersfuntil after the current event cycle.task.cancel(thread)— cancels a thread returned bytask.spawn/task.defer.
For parallel code, task.desynchronize() and task.synchronize() move the current thread between the parallel and serial phases.
Important Services (categorized)
Container / hierarchy services (visible in Explorer, part of the DataModel):
- Workspace (3D content)
- Lighting (environment, atmosphere, post effects)
- ReplicatedStorage / ReplicatedFirst (shared code & assets)
- ServerScriptService (server-only logic)
- StarterGui / StarterPlayer / StarterPack (templates cloned to players)
- Players, Teams, SoundService, etc.
Core runtime & scripting services:
- RunService — Heartbeat fires after physics on both sides; PreSimulation fires before physics on both sides; PreRender is client-only and fires before rendering.
- TweenService (see animation skill)
- CollectionService (tags)
- ContextActionService, UserInputService, GuiService
- ContentProvider (preloading)
Cloud / persistence / cross-server:
- DataStoreService, MemoryStoreService, MessagingService (see roblox-datastores skill)
Monetization:
- MarketplaceService (gamepasses, dev products — see dedicated skill)
- BadgeService, etc.
Other high-value ones: TeleportService, AnalyticsService, HttpService (outbound only + JSONEncode/Decode), PathfindingService, etc.
Discover services with game:GetService (known services) or game:FindService (optional). Avoid using game:GetChildren() for service discovery — not every DataModel child is a service, and services can be lazily created. Acquire each service once per script/module.
Instance Creation Best Practice
Configure an instance before parenting it to avoid redundant replication and extra changed events:
local part = Instance.new("Part")
part.Anchored = true
part.Size = Vector3.new(4, 1, 2)
part.Position = Vector3.new(0, 10, 0)
part.Parent = workspaceSet Parent last; do not use the Instance.new("Part", parent) two-argument form.
Luau Data Types & What You Can Actually Persist
- nil (unique "nothing"; assigning nil to an array index creates a hole, but dictionary keys can conceptually map to nil — the value is still absent from the table)
- boolean
- number (64-bit double; avoid inf/-inf/nan for DataStore/JSON compatibility)
- string (UTF-8; must be valid UTF-8 for DataStores; the
utf8library iterates Unicode codepoints, not grapheme clusters) - table (arrays 1-based or dictionaries; the only complex Luau type)
- Roblox datatypes (Enum.Foo.Bar, CFrame, Vector3, Color3, UDim2, Ray, NumberSequence, ColorSequence, PhysicalProperties, buffer, etc.)
- userdata (rarely used directly in modern Luau; most engine objects are Instances or datatypes)
Note: "tuple" (multiple return values) and Enum are not built-in Luau types. Multiple returns are a language feature, and Enum values are Roblox-specific datatypes.
For DataStores, Remotes, and JSON: Only tables containing the primitives above (no functions, limited cycles, no custom metatables on the saved table itself). Test suspect data with HttpService:JSONEncode during development, but remember that a successful JSONEncode is a sanity check, not a guarantee against every DataStore constraint (e.g. invalid UTF-8, key/size limits).
Data Structures Built on Tables
- Stacks (LIFO) and Queues (FIFO) — easy with table.insert/remove at ends or custom ring buffers.
- Metatables — __index, __newindex, __add, __concat, __len, __call, etc. for class-like behavior, defaults, operator overloading, readonly wrappers.
- Modern table helpers —
table.create,table.find,table.clone,table.freeze/table.isfrozen.
Type Checking
Gradual and opt-in. Use --!strict at the top of a file (it is file-level) or a .luaurc project configuration for project-wide type checking. Add annotations (local x: number, function signatures) for large modules. Inference does a lot of the work. Catches bugs at edit time with zero runtime cost.
Script Locations & Execution Contexts (this is where most bugs originate)
- ServerScriptService + Script (
RunContext.Server) → server only, full power (DataStores, etc.). - ReplicatedStorage → stores shared ModuleScripts/assets. A Script here only runs if its
RunContextis set toClientorServer; use ModuleScripts for shared logic. - StarterGui + LocalScript → per-player client only (inside the cloned PlayerGui).
- ReplicatedFirst + LocalScript → very early client execution (loading screens).
- Actor + Script with
RunContext.Client/Server→ can run Parallel Luau when the code callstask.desynchronize()or usesConnectParallel(). The Actor must be parented to the DataModel and the Script must have an explicit RunContext; placing a Script inside an Actor alone does not parallelize it.require()can be called from parallel contexts only when the module itself is parallel-safe; most engine APIs and many modules are not. - Tools have special execution contexts. HopperBins are deprecated/legacy and should not be used for new work.
Modern Roblox uses BaseScript.RunContext (Legacy, Server, Client, Plugin). Legacy exists only for backward compatibility and is location-dependent; prefer explicit Server or Client for new code. RunContext is set in Studio's Properties window and is read-only at runtime.
Always branch runtime authority with RunService:IsServer() and IsClient(). IsStudio() detects the environment (Studio vs. live), not runtime context, so use it only for test/development guards.
Never put datastore writes, economy, or authoritative gameplay logic anywhere a client can influence it directly.
"Files" and Data in Luau/Roblox
Inside a running experience there is no direct filesystem access (security). You cannot open arbitrary files or write player-visible logs.
What you have instead:
- DataStores / MemoryStores for persistent or temporary "save data".
- ModuleScripts for reusable code (
requireworks like a cached module system: a ModuleScript runs once and returns the same value on subsequent requires). - HttpService:JSONEncode/Decode + web calls for external data exchange.
- In Studio: plugins have limited file APIs, and external tools (Rojo, Script Sync) can sync code from the filesystem, but experience scripts never have arbitrary filesystem access.
For complex data you often serialize tables to JSON strings for storage or transmission.
Important Topics Often Missed
- Attributes — use
:SetAttribute/GetAttributefor lightweight per-instance data; prefer them over legacy Value objects. - Random — use the
Randomclass (Random.new(seed)) for deterministic or independent random streams instead of globalmath.randomseed. - StreamingEnabled — on the client, instances can stream in/out; always use
WaitForChild/Instance.StreamingModedefensively and avoid hard references to far-away parts. - table utilities —
table.create(n, value),table.find(t, value),table.clone(t), andtable.freeze(t)/table.isfrozen(t)are the modern helpers. - BaseScript.Enabled — disables/enables a script without deleting it.
- ModuleScript caching —
requireexecutes a ModuleScript once per environment and caches the returned value. - Sequence / physical types —
NumberSequence,ColorSequence, andPhysicalPropertiesare common Roblox datatypes for particles, beams, and part materials.
Architecture Foundations
- Server authority is the default safe posture.
- Replication is selective and streaming-aware.
- Use ReplicatedStorage for shared modules/assets, ServerScriptService for server logic, StarterGui for client UI entry points.
- CollectionService tags + Attributes for lightweight grouping and data without heavy Instance hierarchies.
- Parallel Luau + Actors when you need CPU-bound work off the main thread.
This skill is the base. Load the specialized skills (datastores, UI, animation, vfx, gamepasses, networking, audio, open-cloud, teleport) on top of it.
Scripts
scripts/ServiceHelper.lua— small utilities for safely acquiring services and requiring modules with timeouts.
Luau Data Types and Serialization Rules
Main sources: https://create.roblox.com/docs/en-us/luau, https://create.roblox.com/docs/en-us/luau/tables, https://create.roblox.com/docs/en-us/luau/type-checking, https://create.roblox.com/docs/en-us/scripting/attributes
Primitive Types
- nil: The only value that represents "nothing". Different from
falseor0. Assigningnilto an array index creates a hole; dictionary tables can conceptually hold a nil value for a key, but in practice the key/value pair is removed andpairswill not visit it. - boolean:
trueorfalse. - number: 64-bit double-precision floating point. Be careful with very large integers and money (consider fixed-point or libraries).
- string: UTF-8 encoded. Must be valid UTF-8 to be stored in DataStores. The
utf8library iterates Unicode codepoints, not grapheme clusters; for UI text that must respect user-perceived characters, additional handling is required. - Enum values:
Enum.Foo.Barvalues (Roblox-specific datatypes, not built-in Luau types).
Tables
The most important type. Can be used as arrays (1-based) or dictionaries.
Important limitations for storage (DataStores, JSON):
- No functions
- No cycles
- No custom metatables on the table being serialized (metatables are not preserved)
- Only the supported primitives inside
Modern table helpers:
table.create(n, value?)— preallocate/initialize arrays efficiently.table.find(t, value, init?)— linear search.table.clone(t)— shallow copy.table.freeze(t)/table.isfrozen(t)— make a table read-only.
Roblox Datatypes / Instances
These are engine objects exposed to Luau:
- Instances (Parts, Models, GUIs, etc.)
- Math / value types: Vector3, CFrame, UDim2, Color3, Ray, Region3, NumberRange, buffer, etc.
typeof()returns the type name (e.g."CFrame","Vector3"). - Sequences / physical types: NumberSequence, ColorSequence, PhysicalProperties — commonly used for particle/beam curves and part physical material settings.
- Attributes — lightweight key/value storage on any Instance via
:SetAttribute/:GetAttribute; prefer over legacy Value objects. - userdata: Rarely used directly in modern Luau; most engine objects are Instances or datatypes.
These have properties and methods but are opaque for pure Luau operations like pairs() in some cases.
Serialization for DataStores vs Networking
DataStores store data as JSON. Supported: nil, boolean, number, string, buffer, and tables containing only those types recursively.
RemoteEvent / RemoteFunction use Roblox's own binary replication, not JSON. They can pass many Roblox datatypes including Instance, Enum, CFrame, Vector3, Color3, etc. — but DataStores still cannot.
Supported after JSON round-trip (DataStores / HttpService):
- nil, boolean, number, string, buffer
- Tables containing only the above (recursively, with no cycles)
Never store in DataStores / JSON:
inf,-inf,nan(they break JSON and can make keys unreadable via Open Cloud)- Functions
- Threads / coroutines
- Instances or other Roblox datatypes (
Vector3,CFrame,Color3,NumberSequence, etc.) unless you convert them to plain tables or strings first - Invalid UTF-8 byte sequences in strings
- Cyclic tables
Debugging tip:
local HttpService = game:GetService("HttpService")
print(HttpService:JSONEncode(yourData))A clean JSONEncode is a good sanity check, but it does not guarantee DataStore success. In particular, DataStores have their own key/value size limits, quotas, and constraints such as invalid UTF-8 and non-finite numbers. nil values become null in JSON but are allowed in DataStores.
Randomness
Use the Random class for deterministic or independent random streams:
local rng = Random.new(12345)
local roll = rng:NextInteger(1, 6)Avoid global math.randomseed in new code; it mutates shared state and can cause surprising interactions across modules.
Type Checking
Luau supports gradual typing:
--!strictis file-level; add it at the top of a script.- A
.luaurcfile is the common way to enable type checking project-wide. - Use annotations:
local gold: number = 100 - Function signatures:
function grantGold(player: Player, amount: number): boolean
This catches many bugs at edit time with zero runtime cost.
See the type-checking subpage for more.
Script Locations, Execution Contexts, and Architecture
Main source: https://create.roblox.com/docs/en-us/scripting/locations Related: https://create.roblox.com/docs/en-us/projects/client-server, https://create.roblox.com/docs/en-us/projects/data-model, https://create.roblox.com/docs/en-us/workspace/streaming, https://create.roblox.com/docs/en-us/scripting/multithreading
Where Code Actually Runs
- ServerScriptService + Script: Runs only on the server. Has full access to DataStoreService, TeleportService, etc. Never replicates to clients. Use
RunContext.Server; theLegacysetting exists only for backward compatibility. - ReplicatedStorage: Holds shared ModuleScripts and assets. A Script placed here only runs if its
RunContextis explicitlyClientorServer; it does not run by default. Put shared logic in ModuleScripts and require them from client/server scripts. - StarterGui + LocalScript: Clones into each player's PlayerGui. Runs only on that client's machine. All UI logic belongs here or in required client modules.
- ReplicatedFirst + LocalScript: Runs as early as possible on the client (before most other content replicates). Use for loading screens and critical early code.
- Actor + Script (placed inside models): Can run Parallel Luau when the Script uses
RunContext.Client/Server, the Actor is parented to the DataModel, and the code explicitly callstask.desynchronize()/task.synchronize()(or usesConnectParallel()). Placing a Script inside an Actor alone does not parallelize it.require()can be called from parallel contexts only when the module itself is parallel-safe; most engine APIs and many modules are not. - Tools have special execution contexts. HopperBins are deprecated/legacy and should not be used for new work.
Modern execution is controlled by BaseScript.RunContext (Legacy, Server, Client, Plugin). Legacy is location-dependent and exists only for backward compatibility; prefer explicit Server/Client for new code. RunContext is set in Studio's Properties window and is read-only at runtime.
Context Checking
Always use:
local RunService = game:GetService("RunService")
if RunService:IsServer() then
-- authoritative logic
elseif RunService:IsClient() then
-- UI, input, prediction, cosmetics
endIsStudio() detects the environment (Studio vs. live), not runtime context. Use it only for test/development guards, never as a substitute for IsServer/IsClient.
Recommended Folder Structure
- ServerScriptService
- DataManager
- Economy
- GamepassHandler
- ServerMain (or multiple small scripts)
- ReplicatedStorage
- Modules (pure functions, constants, types)
- SharedAssets (animations, sounds, models that both sides need)
- Remotes (folder containing all RemoteEvent/RemoteFunction)
- StarterGui
- MainHUD (ScreenGui)
- Menus (multiple ScreenGuis)
- ClientControllers (LocalScripts or folders with required modules)
- Workspace
- Map, interactive objects, etc.
- ServerStorage
- Server-only assets and temporary data.
This structure makes it obvious at a glance which code can do what.
Parallel Luau (Actors)
For CPU-heavy work that doesn't need to yield often: 1. Create an Actor instance. 2. Parent the Actor to the DataModel. 3. Put your Script inside the Actor and set its RunContext to Client or Server. 4. Use task.desynchronize() / task.synchronize() around the heavy work.
This can give significant performance wins for pathfinding, complex simulations, etc.
See the multithreading docs for details and limitations.
Loading Order Realities
Roblox does not guarantee load order. Always use:
WaitForChildFindFirstChild+ defensive checks- Proper initialization events or module setup functions
This is why the "get services → require modules → add functions → connect events" pattern is so reliable.
Script Control
BaseScript.Enabledcan stop or start a Script/LocalScript without deleting it.- A
ModuleScriptruns once per requiring environment and caches its returned value.
Architecture Summary
- Server = truth
- Client = presentation + input
- ReplicatedStorage = shared pure logic and assets
- Clear boundaries + consistent naming prevent most "why doesn't this replicate" and "why can the client do this" bugs.
Master this foundation and all the higher-level skills (data, UI, animation, etc.) become much easier to apply correctly.
Services Catalog and Usage Patterns
Main source: https://create.roblox.com/docs/en-us/scripting/services
The Fundamental Pattern
Every Roblox script almost always starts with:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
-- etc.Acquire each service once per script or module. Name the variable exactly after the service (convention).
Use WaitForChild when requiring modules or waiting for objects whose load order is uncertain.
Container Services (DataModel children)
These form the structure of every place:
- Workspace: Everything that exists in the 3D world.
- Lighting: Global lighting, Atmosphere, Sky, Clouds, post-processing effects.
- ReplicatedStorage: Shared assets and ModuleScripts available to both client and server. ModuleScripts can be required from either side; Scripts here only run with the correct
RunContext. - ReplicatedFirst: Content that must replicate before anything else (use sparingly — mostly for loading screens). LocalScripts here run early.
- ServerScriptService: Server-only scripts and modules (never replicates to clients).
- StarterGui / StarterPlayer / StarterPack: Templates that get cloned into each player.
- Players: Contains all Player instances and their characters.
- SoundService: Global audio configuration and SoundGroups.
For service discovery, use:
game:GetService("ServiceName")for known services.game:FindService("Name")for optional services (returns nil if missing).
GetChildren and GetDescendants return DataModel descendants, not a reliable service list; prefer GetService/FindService for services.
Core Scripting Services
- RunService: PreSimulation fires before physics on both client and server; Heartbeat fires every frame after physics on both sides; PreRender is client-only and fires before rendering; IsServer(), IsClient(), IsStudio(), BindToRenderStep.
- TweenService: Property interpolation (see animation skill).
- CollectionService: Tag instances for easy grouping without folders. Tags replicate.
- ContextActionService: Bind actions to input in a context-aware way (great for tools and menus).
- ContentProvider: PreloadAsync for assets to avoid hitches.
Cloud and Cross-Server Services
- DataStoreService
- MemoryStoreService (high-throughput temporary data)
- MessagingService (publish/subscribe between servers in the same universe)
Monetization & Social
- MarketplaceService
- BadgeService
- GroupService
- AvatarEditorService, AvatarCreationService
Other High-Value Services
- TeleportService
- AnalyticsService
- HttpService (outbound HTTP + JSONEncode/Decode only)
- PathfindingService
- Debris (schedule automatic cleanup of objects)
- GuiService, UserInputService, VRService
Best Practices
- Never call
GetServiceinside a hot loop. - Cache the service reference at the top of the file.
- For optional services, use
FindServiceand check for nil. - Many services have both global methods and events — read the class reference.
- Prefer
task.wait,task.spawn,task.defer, andtask.cancelover deprecatedwait(),spawn(), anddelay().
See the other references in this folder for Luau types, script locations, and architecture.
--!strict
--[[
ServiceHelper.lua
Small utilities for working with Roblox services and modules safely.
local ServiceHelper = require(...)
local Players = ServiceHelper.getService("Players")
local MyModule = ServiceHelper.requireModule("MyModule") -- waits safely
]]
local ServiceHelper = {}
function ServiceHelper.getService(serviceName: string): Instance
return game:GetService(serviceName)
end
local DEFAULT_TIMEOUT: number = 10
function ServiceHelper.requireModule<T>(moduleName: string, parent: Instance?, timeout: number?): T
parent = parent or game:GetService("ReplicatedStorage")
local module = parent:WaitForChild(moduleName, timeout or DEFAULT_TIMEOUT)
if module and module:IsA("ModuleScript") then
return require(module) :: T
end
error("Module not found or not a ModuleScript: " .. moduleName)
end
return ServiceHelper