Native Luau Vector3 Beta

Hey developers,

As we continue our work on Luau VM performance, one of the items we wanted to address was performance of Vector3 operations.

Vector3s used to be heap-allocated, meaning that memory allocation took place for every vector, and only de-allocated by garbage collection - which was having a negative impact on performance. This particularly impacts code that creates a lot of short-lived temporary vectors, which could trigger a lot of garbage collection steps. Another important area is binary operations between vectors that were implemented using metatable function and even a simple addition would have to go through a function call.

Internally, our VM has supported a built-in ‘vector’ value type for some time now with built-in vector operations, but the Roblox Vector3 userdata class didn’t use that machinery.

After additional development, we are now ready to switch Vector3 userdata to use our vector value type! You should expect performance improvements for property accesses and all existing operations. You can even use Vector3 to vectorize your scalar code for an improvement in performance.

The Native Vector3 Type can be enabled via the Roblox Studio Beta Features Menu:

But while we tried to make this change backwards-compatible and our Vector3 userdata implementation tried to emulate an immutable value type like the built-in vector, underlying type change does bring behavior changes that can be seen from outside:

  • type( will now return ‘vector’ instead of ‘userdata’. Note that the separate function, typeof( will continue to return Vector3 as it did before.
  • Vector3 is now a value type, which changes the result of rawequal for Vector3 values that were created separately, but hold the same value. This also means that rawequal(v, v) will return false if one of the vector components is NaN.
  • If you’ve used Vector3 as a table key, instances holding the same value will now be compared equally
  • If you’ve used Vector3 as a weak table key, these table entries will no longer be collected. If you use such tables for caching, you should switch to an explicit caching scheme.

We are launching this as Beta so that you will be able to test your games and report problems that arise from the underlying type change. We would also like to hear how your Vector3-heavy code performance is improved!

If we don’t discover any significant issues we plan to enable this change for game clients and servers by default in a few weeks. Please let us know if your game may be negatively impacted by this change.

The Roblox Team

edit: clarified the behavior of typeof


This topic was automatically opened after 18 minutes.

Honestly I’m super impressed! This has been long overdue. What does the performance of this compare to CFrame. Up until now, CFrames were more efficient, even without using orientation. Has that changed? Should I use this over CFrames when there is no need for orientation? Or has this change not affected the way changing the direct position of an object at all?

Also I think the type function should return “Vector3”, because if you have any plans for making Vector2’s native, there would be no easy way to tell them apart using the type function.


will this be for vector2 also? cframes?


Is this to make room for a potentially native Vector2? But that wouldn’t make sense either, since you couldn’t be able to make a distinction between Vector3 and Vector2 through type() at runtime.

Also will “vector” be a type alias for Vector3?


typeof still returns Vector3 as it did before


Since a bunch of scripts by default already have to use Vector values, (cameras, characters, etc) should we expect to see a noticeable performance improvement just from enabling this?

This won’t break any of my stuff because I don’t use type(), I only use typeof() anyway, and you guys should too.

Overall, it’s a welcomed change. I don’t see much wrong with it which would cause huge issues.


If I am correct, CFrames are already native.

Nice! Our code is optimized even more now! :smile:

And just to be clear, we don’t have to update our existing code, right?

I’m also curious - are there plans to extend this sort of native implementation to other data types? I realize it makes less since but it might be worth it for e.g. CFrame.

1 Like

Indeed. For example, you will see a 20% (!) performance improvement in dragging content with Join Surfaces enabled using the studio draggers, because that code makes very heavy use of Vector3 math.


I know that, and I believe scripts should be doing runtime checks through typeof anyway, that is why I said through type. Still seems odd to me that type( ~= typeof( with this update, hence my question, if “vector” will be a generic representation for Vector(2/3)

1 Like

The performance improvement with this change sounds great. But that raises a question for me. Are you guys planning to implement something like this for other DataTypes that people heavily use for math operations for noticeable performance improvements also? Like CFrame, for example?


No you do not, unless you use the type function on a vector3. I is just backend changes.

1 Like

That’s really good to see. I thought the differences were like ‘oh yeah 2%’, but I’m impressed, I like this update,

I don’t see it breaking anything for people who don’t have weird hacky code. I never really saw anyone depend on type() returning ‘userdata’ for Vector3s. Usually the other way around, but people often use type for either checking if something is a certain type, or to make table to folder and values type of stuff, which people use typeof() anyway.

Thanks for the update!

Calling typeof with a Vector3 object will return Vector3. typeof is for Roblox datatypes and type is for native Luau datatypes.

1 Like

To be fair, of the official Lua code written by Roblox, the studio draggers are the code that will get by far the biggest improvement, since they do by far the most raw Vector math. Most code will be getting significantly more modest improvements.


Wow, I have been waiting for something like this to happen for quite a while now. Nice job!

Also, regarding native CFrame, wouldn’t they already get some sort of performance boost? Since they are really just glorified Vector3s.


This is amazing! My capsule collider that’s designed with a triangle-vs-capsule algorithm uses a lot of Vector3 math, now it’s way faster!


Old Vector3 behavior:

New Vector3 behavior: