Reference

Changelog

Full version history. Entries marked breaking require code changes when upgrading. See the Migration guide for step-by-step instructions.

v2.5.0 current

Typing | Added

  • Types.luau | new standalone module — explicit public types for every module, no private field leakage
  • RoExpressCall overloaded intersection type — RoExpress("App") now returns RoExpress.App, not any
  • Autocomplete for module name strings in the call form | Luau suggests all valid module names
  • Route handler (req, res) parameters fully inferred — no manual annotation required
  • All exported types forwarded from Types.luau via the root module

Init | Changed

  • Lazy loading via __index + rawset cache — modules load on first access, not on require
  • Pre-baked RemoteEvent and UnreliableRemoteEvent stored as package children — no timing race between server and client
  • GetApp() and GetNetwork() removed — call form is now fully typed and covers all use cases

Bridge | Changed breaking

  • BindOn | now returns a BridgeConnection object with :Disconnect()
  • BindOnceOnce | same connection object, fires handler at most once
  • FireEmit
  • UnbindAllClear
  • Unbind removed — use the connection returned by On / Once instead
  • Has, Wait, WaitUntil, WaitFirst, Destroy retained unchanged

Maid | Added

  • New Maid module — lifecycle cleanup utility, works everywhere (server and client)
  • RoExpress("Maid") returns a fresh instance each call
  • Add<T>(item) returns item unchanged — store and track in one expression
  • Duck-typed cleanup: RBXScriptConnection, BridgeConnection, any :Destroy() table, threads, and plain functions
  • Nesting supported — a child Maid added to a parent Maid is cleaned up when the parent is destroyed

Debounce | Added

  • New Debounce module — cooldown wrappers for functions
  • Debounce.fn(fn, cooldown) | global shared cooldown timer
  • Debounce.key(fn, cooldown) | independent per-first-argument cooldown (standard per-player pattern)
  • Returns true when the call went through, false when blocked by cooldown

Installer | Changed

  • RemoteEvent and UnreliableRemoteEvent now created as children of the RoExpress ModuleScript
  • Maid, Debounce, and Types added to installer flat module list (28 total)

v2.4.0

Stream | Added

  • Stream:Schema(fields) | compile-time binary layout, fixed offsets, delta-compression
  • Stream:Channel(name, schema, options?) | typed binary channel instance
  • channel:Send(data) | client-to-server send over UnreliableRemoteEvent
  • channel:Subscribe(fn) | server subscription with automatic delta decompression
  • channel:Unsubscribe(id) | remove subscription
  • 20 built-in wire types: uint8, uint16, uint32, int8, int16, int32, float32, float64, bool, string8, string16, Vector2, Vector3, Color3, CFrame, UDim2, Rect, Enum, Instance, BrickColor
  • Custom type registration via Stream:RegisterType(name, size, pack, unpack)
  • Per-channel rate limiting with sequence number tracking and gap recovery

Typing | Changed

  • RoExpress.GetApp() | new typed accessor, returns App instance (fully typed)
  • RoExpress.GetNetwork() | new typed accessor, returns Network instance (fully typed)
  • All inner types now export type | forward-referenced from source, can never drift
  • New exported types: RouteHandlerCompact, RouteHandlerLegacy, RouteHandler, MiddlewareHandler
  • Payload.method expanded to "GET" | "POST" | "PUT" | "DELETE" (was missing PUT/DELETE)
  • Request now includes captures, player?, raw? fields (previously missing)
  • NetworkResponse now includes compressed: boolean?
  • export type App/Network/Port now use .Type (instance shape) not typeof(require())

Stream (pre-v2.4 API) | Removed breaking

  • Removed Stream:Sender() and Stream:Receiver() | FPS-tick model
  • Removed v2 Stream.Channel type shape

v2.3.0

Added

  • PUT and DELETE methods on App and Port
  • Compact handler form (req, res) → () | auto-detected by parameter count via debug.info
  • req.player and req.raw fields populated in compact handlers
  • LZH (Deflate) compression in Codec | better ratio than LZ77 for large payloads
  • Automatic retry on Network timeout (2 retries, exponential backoff)
  • options.compress = true on route registration | auto-compresses response, auto-decompresses on client

v2.2.0

Added

  • TypeCoercer module | typed route params (number, int, boolean, Vector2, Vector3, CFrame, Color3, Enum, Instance)
  • Range constraints on int params: :n=int[1,100]
  • Promise module | chainable async Network API (GetAsync, PostAsync etc.)
  • Version module | runtime version access

v2.1.0

Added

  • Stream (pre-v2.4) | FPS-tick based binary streaming (superseded in v2.4)
  • Named Ports | app:Listen(name, fn, settings) with isolated RemoteEvent and TokenBucket
  • app:GetPort(name) | get Port reference after creation

v2.0.0

Added

  • Router | typed named params, wildcards, globs, route priority
  • Server Push | app:Push(), app:PushAll(), app:PushTo() over reliable RemoteEvent
  • Codec | LZ77 compression for large payloads
  • Bridge | internal server-side event bus
  • Tamper | passive exploit detection, strike system, version checking
  • Broadcast | unreliable server-to-client fire-and-forget via UnreliableRemoteEvent
  • Listener | client-side handler for both Broadcast and Push events

See also

Migration guide | step-by-step upgrade instructions  ·  GitHub Releases