canaryThese pages document the canary: an unreleased build. What they describe may not be in the version you have, and may change before it is.The stable build
Try it in your browsercanary Source

Functions✎

The two ways to declare one, the graph each opens in, how to call it, and what can reach inside.

Verified

Every function in a nodescript has a graph of its own. Its body is built there, it opens in a tab, and the nodescript's own graph stays about the script's flow.

Functions are the language's, not the engine's, so everything on this page works the same whether the graph compiles for Roblox or for Lune.

Two ways to declare one

NodeWrittenDrawn in
FunctionAt the top of the file, so anything can call itIts own graph only, as the entry node
Declare FunctionWhere the node sits in the flow, or onto a table with On TableThe flow, and its own graph as the entry node
Function() → ()−+Function
Declare Function() → ()−+BodyOn TableFunction
As the reference draws them, with every pin. On the canvas Declare Function shows half of these in each of its two graphs.

Reach for Declare Function when the function has to come after something — function TankConfig.read(tank: Model) needs TankConfig to exist first — and for Function when it is simply something the script has.

Info

On Table must resolve to a variable or a local; Luau cannot attach a function to an expression. Left unwired, it is a plain local function.

The signature

Name, parameters and return values are all edited in the Inspector, on either declaration node. The signature is written under the node's header — read(tank: Model): Config — so a graph full of functions can be read without opening any of them.

FieldWhat it does
NameWhat the function is called, and what a Get Function offers
ParametersName and optional Luau type each. They become data outputs on the entry node, in this order
Return valuesName and optional Luau type each. They become input pins on every Return in this function

A type here is free text, the same as a local's or a variable's: BasePart?, { [Model]: Restore } and a union are all types no dropdown could offer. Left blank there is no annotation at all rather than any.

Renaming a parameter carries every node reading it along. Reordering them leaves those nodes alone, because a Get Parameter holds the parameter's name and not its position. Removing one leaves the node saying which parameter is gone.

A function's graph

It opens in a tab marked ƒ and named for the function and its script: hide (Occupancy). Shorten function tabs in settings keeps one of the two names. The entry node carries Body and the parameters, and the function's Return nodes go in this graph too.

  • In the project tree, the arrow beside a .nodescript lists its functions. Double-click one to open it.
  • Click a function in the Variables panel.
  • Double-click a Declare Function in the flow, or click the ƒ on its header.
  • Adding a Function opens its graph straight away.

P with nothing selected previews the function you are in, rather than the whole script. The nodescript's own graph still previews all of it.

Declare Function, in two graphs

GraphIts pins there
The flow it is declared inIn, Then, On Table, and Function — the function as a value
Its own graphBody, and one output per parameter

It is one node with a place in each. Moving it in one graph does not move it in the other, and renaming it or changing its parameters shows in both.

Returning

Return ends the enclosing function, and it lives in that function's graph. Give the function return values in the Inspector and each one becomes a pin on every Return in it — named, typed, and with a default you can type in rather than having to wire a node up for a constant.

Return−+
A Return with no values configured is the bare return. Each value you add to the signature adds a pin here.

Info

A function with no Return is fine: it returns nothing, like the Luau it compiles to.

Calling one

A function is reached as a value first, and then called. Get Function is that value for a function declared in this graph; the Function output on either declaration node is the same thing, which is what lets one be handed to Connect or returned from a module without a wrapper node.

NodeWhen
Call FunctionThe call does something. It sits in the execution chain and binds its result to a local
Call For ValueThe call asks something. No execution wire, so it goes where a value goes — inside a table, an argument, an expression
Call MethodThe call is colon-style, on an object: part:Destroy(). See Services and their methods for the service case
Get Function
Call Function−+ResultFunctionArgument
Call For ValueFunctionArgument
Both call nodes take the function on a wire, and the argument count is set in the Inspector rather than fixed by the node.
luau
-- Call Function: the result is bound, and the order is on the wire
local config = TankConfig.read(tank)

-- Call For Value: spliced into whatever reads it
return { movementSpeed = readNumber(hullSettings, "MovementSpeed") }

Warning

A Get Function earlier in the flow than its Declare Function is an error. A hoisted Function has no order to get wrong.

Reading a parameter

The parameter pins on the entry node work and are not going away, but in a function of any size the wires off them cross the whole body. Get Parameter reads one by name instead — the same trade Get Local makes. Pick the function and the parameter in the Inspector.

Get Parameter
  • It works inside an event handler as well as a function: Connect binds its handler's parameters in the same way.
  • Typing a parameter's name into the node search offers Get ‹parameter› directly, with From and Parameter already filled in.
  • A parameter is offered only inside the body it belongs to — a function's in its own graph, a handler's where its node is drawn.

Warning

A Get Parameter outside its function's body creates an error pointing to both.

Finding one

The Variables panel lists every function this script declares, under its own heading. Click one to open its graph; drag it onto the canvas for a Get Function.

Everything this script declares: its variables, its modules, its locals and its functions.

Hover a control or its row to light the other.

  • VariablesValues the whole script reads and writes. See Variables and locals.
  • ModulesWhat this script requires, one require each. See Modules.
  • LocalsValues that exist inside one block. See Variables and locals.
  • FunctionsEvery function this script declares. Clicking one opens its graph, which is how you move between them — a declaration in a graph of any size is off screen.

Both node searches know them too. This graph, in the node menu's filter row, sets the built-in library aside and leaves what this graph declares: its variables, locals, functions and — in a function's own graph — that function's parameters. Ctrl + right-click opens the same list as the node picker, with each entry drawn as you walk it.

What reaches inside

A wire cannot run between two graphs. A value reaches a function through a parameter — wired from the entry node, or read with Get Parameter — through a local declared before it, or through a script variable. Anything you add in a function's tab goes in that function's graph.

Which locals count as before it is the one place the two declarations differ. A Declare Function is written where it sits, so it closes over the file's locals and the Variables panel lists them inside it. A hoisted Function is written above them, so it cannot see them and they are not offered.

Warning

A wire between two graphs can only come from a hand-edited file or a bad merge, and it creates an error on the node it runs into.

Editing a function as a whole

  • Select all, marquee select, Realign and align act on the graph on screen, and only that.
  • Deleting a function deletes its graph, and asks first when there are nodes in it. Its tab closes.
  • Copying a function copies its graph, so the paste is a working function. Only its declaration lands at the pointer; the nodes inside keep their places.

Last reviewed 16 September 2026 by @neopolitans