Installation
OwlKnit lives in ReplicatedStorage.OwlKnit, same as any Wally package. Once it's in your project, starting the framework only takes two calls per side: load your modules, then Owl.Start().
Server
Load every Service from a folder, then start the framework. Owl.Start() returns a promise that resolves once every OwlInit/OwlStart phase across all Services has completed.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Owl = require(ReplicatedStorage.OwlKnit.Owl)
-- > // 1. Load every Service from a folder
Owl.AddServices(script.Parent.Services)
-- > // 2. Start (with optional config)
Owl.Start({
Verbose = true,
GlobalMiddleware = {
Inbound = {
Owl.Util.RateLimiter.perPlayer(30, 1, "Global"),
},
},
}):andThen(function()
print("Owl Server started!")
end):catch(warn)Client
Same shape with Controllers instead of Services. There's no GlobalMiddleware on the client, middleware is a server-side security concern, covered in Middleware.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Owl = require(ReplicatedStorage.OwlKnit.Owl)
-- > // 1. Load every Controller from a folder
Owl.AddControllers(script.Parent.Controllers)
-- > // 2. Start
Owl.Start():andThen(function()
print("Owl Client started!")
end):catch(warn)Configuration
Owl.Config can be edited before Owl.Start(). Once the framework has started, the config table is frozen (table.freeze), any attempt to modify it afterwards throws an error.
| Key | Type | Default | Description |
|---|---|---|---|
Verbose |
boolean |
false |
Enables [Owl][INFO] debug logs |
InitTimeout |
number |
30 |
Timeout in seconds for the OwlInit phase |
StartTimeout |
number |
30 |
Timeout in seconds for the OwlStart phase |
GlobalMiddleware |
table |
{} |
Global middleware applied to every remote |
Backend |
string |
ProfileStore/DataStore2 |
Type of data used (ProfileStore recommended) |
AutoSave |
boolean |
true |
Allow autosave for datas |
SaveInterval |
number |
60 |
How many times before autosave |
For the three last (Backend, AutoSave and SaveInterval), check (see OwlData)
You can set these either directly on Owl.Config or inline as the first argument to Owl.Start(), both are equivalent but passing everything to Owl.Start() is the recommended style since it keeps your whole config in one place.
Owl.Start({
Verbose = true,
InitTimeout = 60,
StartTimeout = 60,
GlobalMiddleware = {
Inbound = { Owl.Util.RateLimiter.perPlayer(30, 1, "Global") },
},
Data = {
Backend = "ProfileStore",
AutoSave = true,
SaveInterval = 60,
},
}):catch(warn)
Owl.Start()rejects if any Service or Controller throws duringOwlInitor if a phase exceeds its timeout. Always attach a:catch(warn), a silent failure at startup is much harder to debug than a loud one.
Where to go next
- Want to see it end-to-end? First Project walks through creating one real Service and Controller together.
- Coming from Knit? Check Owl vs Knit - the startup sequence above is one of the few things that stayed identical on purpose.