Hey everyone!
Ive been working on my own framework for a while and finally decided to share it. I got tired of rewriting the same stuff (networking, player data, module loading) for every new project, so I built this for myself. Maybe someone else will find it useful
Its pretty simple. You split your code into modules with lifecycle hooks, and the framework handles the rest: dependency injection, player/character events, heartbeat updates, and network contracts
This is a solo project built from scratch to solve my own workflow needs. Its not a clone of anything - just my personal take on a lightweight framework
Quick Start: Install the Nextinel Builder Plugin to auto-generate the entire folder structure and typed boilerplate modules in one click
Example (server code):
So instead of writing manually
local players = game:GetService("Players")
function CharacterAdded(character: Model)
local humanoid = character:WaitForChild("Humanoid")
local root = character:WaitForChild("HumanoidRootPart")
...
end
function PlayerAdded(player: Player)
player.CharacterAdded:Connect(CharacterAdded)
end
players.PlayerAdded:Connect(PlayerAdded)
You can write it that way:
local replicatedStorage = game:GetService("ReplicatedStorage")
local Types = require(replicatedStorage.Modules.Global.Types)
return {
characterLoaded = function(character, humanoid, root, player)
...
end,
} :: Types.ServerModule
No need to call WaitForChild manually - the framework waits for the Humanoid and RootPart to exist before calling this hook
Under the hood
- Nextinel Builder: Studio plugin for one-click setup and generating typed modules
- Type Safety: Built-in
Types.ServerModuleandTypes.ClientModulefor full IntelliSense on all hooks - Error Tracebacks: Filtered
xpcalltracebacks that point directly to your module, hiding framework internals - Heartbeat buckets: To update modules across 3 buckets so it doesnât lag
- Jolt API: For networking, with
Network contractsfor runtime type validation - DataStoreService: Built on
ProfileStorewith Migrator, typed profiles, and:observe()methods - HangWatcher: Warns if a moduleâs
inittakes longer than 10s - Dependency Injection: Modules declare dependencies, resolved with priority
Why Nextinel?
Unlike heavier frameworks, Nextinel gives you a lightweight base. You get the routine handled for you, but you keep full control over your architecture. No bloat, no magic
Known Limitations
Note: Dependencies are still string-based for simplicity (dependencies = {"ModuleName"} ). This means dependingServices wonât have autocomplete inside init(), but all lifecycle hooks are now fully typed
Full API Reference
Server module hooks:
return {
dependencies = {"ModuleName"}, -- optional
init = function(dependingServices) end,
update = function(deltaTime) end,
playerAdded = function(player) end,
playerDataLoaded = function(player, profile) end,
playerRemoving = function(player) end,
characterAdded = function(character, player) end,
characterLoaded = function(character, humanoid, root, player) end,
humanoidAdded = function(humanoid, player) end,
characterRemoved = function(character, player) end,
network = {
channel = "ChannelName",
shouldCheckExtrafields = false, -- optional (default: true)
contract = {[1] = "string", [2] = "number"}, -- optional
onEvent = function(name, count) end,
},
}
Client module hooks:
local channels = {}
--[[
to call fireServer:
channels.ChannelName:fireServer(...)
]]
return {
dependencies = {"ModuleName"}, -- optional
init = function(dependingServices) end,
asyncInit = function() end, -- runs asynchronously (wrapped in task.spawn)
update = function(deltaTime) end,
clientReady = function() end,
characterAdded = function(character) end,
characterLoaded = function(character, humanoid, root) end,
humanoidAdded = function(humanoid) end,
characterRemoved = function(character) end,
network = {
channel = "ChannelName",
shouldCheckExtrafields = false, -- optional (default: true)
contract = {[1] = "string", [2] = "number"}, -- optional
onEvent = function(name, count) end,
},
setupFireServer = {
channelsNames = {"ChannelName"},
setupRemote = function(name, network)
channels[name] = network
end,
},
}
Note: asyncInit is called after init but runs asynchronously, so it doesnât block the main thread
Updates (Posts)
v1.1.0 Network changes: Click
v1.1.1 Logger & Types: Click
v2.0.0 DataStore Module Rework: Click
v2.1.0 HangWatcher, Priorities & Profile Methods: Click
v2.2.0 Nextinel Builder & Type Safety: Click
GitHub
I put full docs and installation instructions in the README. Download link is in Releases
GitHub Repo